Following what was already done for GL.
#include "gskbroadwayrendererprivate.h"
#endif
#ifdef GDK_RENDERING_VULKAN
-#include "gskvulkanrendererprivate.h"
+#include "vulkan/gskvulkanrendererprivate.h"
#endif
typedef struct
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanblendmodepipelineprivate.h"
-
-struct _GskVulkanBlendModePipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanBlendModeInstance GskVulkanBlendModeInstance;
-
-struct _GskVulkanBlendModeInstance
-{
- float rect[4];
- float start_tex_rect[4];
- float end_tex_rect[4];
- guint32 blend_mode;
-};
-
-G_DEFINE_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_blend_mode_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanBlendModeInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = 0,
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, start_tex_rect),
- },
- {
- .location = 2,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, end_tex_rect),
- },
- {
- .location = 3,
- .binding = 0,
- .format = VK_FORMAT_R32_UINT,
- .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, blend_mode),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_blend_mode_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanBlendModePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_blend_mode_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_blend_mode_pipeline_class_init (GskVulkanBlendModePipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_blend_mode_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_blend_mode_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_blend_mode_pipeline_init (GskVulkanBlendModePipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_blend_mode_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline)
-{
- return sizeof (GskVulkanBlendModeInstance);
-}
-
-void
-gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
- guchar *data,
- const graphene_rect_t *bounds,
- const graphene_rect_t *start_tex_rect,
- const graphene_rect_t *end_tex_rect,
- GskBlendMode blend_mode)
-{
- GskVulkanBlendModeInstance *instance = (GskVulkanBlendModeInstance *) data;
-
- instance->rect[0] = bounds->origin.x;
- instance->rect[1] = bounds->origin.y;
- instance->rect[2] = bounds->size.width;
- instance->rect[3] = bounds->size.height;
-
- instance->start_tex_rect[0] = start_tex_rect->origin.x;
- instance->start_tex_rect[1] = start_tex_rect->origin.y;
- instance->start_tex_rect[2] = start_tex_rect->size.width;
- instance->start_tex_rect[3] = start_tex_rect->size.height;
-
- instance->end_tex_rect[0] = end_tex_rect->origin.x;
- instance->end_tex_rect[1] = end_tex_rect->origin.y;
- instance->end_tex_rect[2] = end_tex_rect->size.width;
- instance->end_tex_rect[3] = end_tex_rect->size.height;
-
- instance->blend_mode = blend_mode;
-}
-
-gsize
-gsk_vulkan_blend_mode_pipeline_draw (GskVulkanBlendModePipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskenums.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBlendModePipelineLayout GskVulkanBlendModePipelineLayout;
-
-#define GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE (gsk_vulkan_blend_mode_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK, VULKAN_BLEND_MODE_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_blend_mode_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline);
-void gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
- guchar *data,
- const graphene_rect_t *bounds,
- const graphene_rect_t *start_bounds,
- const graphene_rect_t *end_bounds,
- GskBlendMode blend_mode);
-gsize gsk_vulkan_blend_mode_pipeline_draw (GskVulkanBlendModePipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanblurpipelineprivate.h"
-
-struct _GskVulkanBlurPipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanBlurInstance GskVulkanBlurInstance;
-
-struct _GskVulkanBlurInstance
-{
- float rect[4];
- float tex_rect[4];
- float blur_radius;
-};
-
-G_DEFINE_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_blur_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanBlurInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = 0,
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, tex_rect),
- },
- {
- .location = 2,
- .binding = 0,
- .format = VK_FORMAT_R32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, blur_radius),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_blur_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanBlurPipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_blur_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_blur_pipeline_class_init (GskVulkanBlurPipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_blur_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_blur_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_blur_pipeline_init (GskVulkanBlurPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_blur_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLUR_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_blur_pipeline_count_vertex_data (GskVulkanBlurPipeline *pipeline)
-{
- return sizeof (GskVulkanBlurInstance);
-}
-
-void
-gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const graphene_rect_t *tex_rect,
- double blur_radius)
-{
- GskVulkanBlurInstance *instance = (GskVulkanBlurInstance *) data;
-
- instance->rect[0] = rect->origin.x;
- instance->rect[1] = rect->origin.y;
- instance->rect[2] = rect->size.width;
- instance->rect[3] = rect->size.height;
- instance->tex_rect[0] = tex_rect->origin.x;
- instance->tex_rect[1] = tex_rect->origin.y;
- instance->tex_rect[2] = tex_rect->size.width;
- instance->tex_rect[3] = tex_rect->size.height;
- instance->blur_radius = blur_radius;
-}
-
-gsize
-gsk_vulkan_blur_pipeline_draw (GskVulkanBlurPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBlurPipelineLayout GskVulkanBlurPipelineLayout;
-
-#define GSK_TYPE_VULKAN_BLUR_PIPELINE (gsk_vulkan_blur_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK, VULKAN_BLUR_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_blur_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_blur_pipeline_count_vertex_data (GskVulkanBlurPipeline *pipeline);
-void gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const graphene_rect_t *tex_rect,
- double radius);
-gsize gsk_vulkan_blur_pipeline_draw (GskVulkanBlurPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanborderpipelineprivate.h"
-
-#include "gskroundedrectprivate.h"
-
-struct _GskVulkanBorderPipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanBorderInstance GskVulkanBorderInstance;
-
-struct _GskVulkanBorderInstance
-{
- float rect[12];
- float widths[4];
- float colors[16];
-};
-
-G_DEFINE_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_border_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanBorderInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect),
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 4 * sizeof (float),
- },
- {
- .location = 2,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 8 * sizeof (float),
- },
- {
- .location = 3,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, widths),
- },
- {
- .location = 4,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors),
- },
- {
- .location = 5,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 4 * sizeof (float),
- },
- {
- .location = 6,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 8 * sizeof (float),
- },
- {
- .location = 7,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 12 * sizeof (float),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_border_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanBorderPipeline *self = GSK_VULKAN_BORDER_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_border_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_border_pipeline_class_init (GskVulkanBorderPipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_border_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_border_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_border_pipeline_init (GskVulkanBorderPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_border_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BORDER_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline)
-{
- return sizeof (GskVulkanBorderInstance);
-}
-
-void
-gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
- guchar *data,
- const GskRoundedRect *rect,
- const float widths[4],
- const GdkRGBA colors[4])
-{
- GskVulkanBorderInstance *instance = (GskVulkanBorderInstance *) data;
- guint i;
-
- gsk_rounded_rect_to_float (rect, instance->rect);
- for (i = 0; i < 4; i++)
- {
- instance->widths[i] = widths[i];
- instance->colors[4 * i + 0] = colors[i].red;
- instance->colors[4 * i + 1] = colors[i].green;
- instance->colors[4 * i + 2] = colors[i].blue;
- instance->colors[4 * i + 3] = colors[i].alpha;
- }
-}
-
-gsize
-gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6 * 8, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskroundedrect.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBorderPipelineLayout GskVulkanBorderPipelineLayout;
-
-#define GSK_TYPE_VULKAN_BORDER_PIPELINE (gsk_vulkan_border_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK, VULKAN_BORDER_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_border_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline);
-void gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
- guchar *data,
- const GskRoundedRect *rect,
- const float widths[4],
- const GdkRGBA colors[4]);
-gsize gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanboxshadowpipelineprivate.h"
-
-#include "gskroundedrectprivate.h"
-
-struct _GskVulkanBoxShadowPipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanBoxShadowInstance GskVulkanBoxShadowInstance;
-
-struct _GskVulkanBoxShadowInstance
-{
- float outline[12];
- float color[4];
- float offset[2];
- float spread;
- float blur_radius;
-};
-
-G_DEFINE_TYPE (GskVulkanBoxShadowPipeline, gsk_vulkan_box_shadow_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_box_shadow_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanBoxShadowInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline),
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 4 * sizeof (float),
- },
- {
- .location = 2,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 8 * sizeof (float),
- },
- {
- .location = 3,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, color),
- },
- {
- .location = 4,
- .binding = 0,
- .format = VK_FORMAT_R32G32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, offset),
- },
- {
- .location = 5,
- .binding = 0,
- .format = VK_FORMAT_R32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, spread),
- },
- {
- .location = 6,
- .binding = 0,
- .format = VK_FORMAT_R32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, blur_radius),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_box_shadow_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanBoxShadowPipeline *self = GSK_VULKAN_BOX_SHADOW_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_box_shadow_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_box_shadow_pipeline_class_init (GskVulkanBoxShadowPipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_box_shadow_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_box_shadow_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_box_shadow_pipeline_init (GskVulkanBoxShadowPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_box_shadow_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BOX_SHADOW_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline *pipeline)
-{
- return sizeof (GskVulkanBoxShadowInstance);
-}
-
-void
-gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *pipeline,
- guchar *data,
- const GskRoundedRect *outline,
- const GdkRGBA *color,
- float dx,
- float dy,
- float spread,
- float blur_radius)
-{
- GskVulkanBoxShadowInstance *instance = (GskVulkanBoxShadowInstance *) data;
-
- gsk_rounded_rect_to_float (outline, instance->outline);
- instance->color[0] = color->red;
- instance->color[1] = color->green;
- instance->color[2] = color->blue;
- instance->color[3] = color->alpha;
- instance->offset[0] = dx;
- instance->offset[1] = dy;
- instance->spread = spread;
- instance->blur_radius = blur_radius;
-}
-
-gsize
-gsk_vulkan_box_shadow_pipeline_draw (GskVulkanBoxShadowPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6 * 8, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskroundedrect.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBoxShadowPipelineLayout GskVulkanBoxShadowPipelineLayout;
-
-#define GSK_TYPE_VULKAN_BOX_SHADOW_PIPELINE (gsk_vulkan_box_shadow_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanBoxShadowPipeline, gsk_vulkan_box_shadow_pipeline, GSK, VULKAN_BOX_SHADOW_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_box_shadow_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline *pipeline);
-void gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *pipeline,
- guchar *data,
- const GskRoundedRect *outline,
- const GdkRGBA *color,
- float dx,
- float dy,
- float spread,
- float blur_radius);
-
-gsize gsk_vulkan_box_shadow_pipeline_draw (GskVulkanBoxShadowPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanbufferprivate.h"
-#include "gskvulkanmemoryprivate.h"
-#include "gskvulkanpipelineprivate.h"
-
-struct _GskVulkanBuffer
-{
- GdkVulkanContext *vulkan;
-
- gsize size;
-
- VkBuffer vk_buffer;
-
- GskVulkanMemory *memory;
-};
-
-static GskVulkanBuffer *
-gsk_vulkan_buffer_new_internal (GdkVulkanContext *context,
- gsize size,
- VkBufferUsageFlags usage)
-{
- VkMemoryRequirements requirements;
- GskVulkanBuffer *self;
-
- self = g_slice_new0 (GskVulkanBuffer);
-
- self->vulkan = g_object_ref (context);
- self->size = size;
-
- GSK_VK_CHECK (vkCreateBuffer, gdk_vulkan_context_get_device (context),
- &(VkBufferCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
- .size = size,
- .flags = 0,
- .usage = usage,
- .sharingMode = VK_SHARING_MODE_EXCLUSIVE
- },
- NULL,
- &self->vk_buffer);
-
- vkGetBufferMemoryRequirements (gdk_vulkan_context_get_device (context),
- self->vk_buffer,
- &requirements);
-
- self->memory = gsk_vulkan_memory_new (context,
- requirements.memoryTypeBits,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- size);
-
- GSK_VK_CHECK (vkBindBufferMemory, gdk_vulkan_context_get_device (context),
- self->vk_buffer,
- gsk_vulkan_memory_get_device_memory (self->memory),
- 0);
- return self;
-}
-
-GskVulkanBuffer *
-gsk_vulkan_buffer_new (GdkVulkanContext *context,
- gsize size)
-{
- return gsk_vulkan_buffer_new_internal (context, size,
- VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
- | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
-}
-
-GskVulkanBuffer *
-gsk_vulkan_buffer_new_staging (GdkVulkanContext *context,
- gsize size)
-{
- return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
-}
-
-GskVulkanBuffer *
-gsk_vulkan_buffer_new_download (GdkVulkanContext *context,
- gsize size)
-{
- return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
-}
-void
-gsk_vulkan_buffer_free (GskVulkanBuffer *self)
-{
- vkDestroyBuffer (gdk_vulkan_context_get_device (self->vulkan),
- self->vk_buffer,
- NULL);
-
- gsk_vulkan_memory_free (self->memory);
-
- g_object_unref (self->vulkan);
-
- g_slice_free (GskVulkanBuffer, self);
-}
-
-VkBuffer
-gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self)
-{
- return self->vk_buffer;
-}
-
-guchar *
-gsk_vulkan_buffer_map (GskVulkanBuffer *self)
-{
- return gsk_vulkan_memory_map (self->memory);
-}
-
-void
-gsk_vulkan_buffer_unmap (GskVulkanBuffer *self)
-{
- gsk_vulkan_memory_unmap (self->memory);
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_BUFFER_PRIVATE_H__
-#define __GSK_VULKAN_BUFFER_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanBuffer GskVulkanBuffer;
-
-GskVulkanBuffer * gsk_vulkan_buffer_new (GdkVulkanContext *context,
- gsize size);
-GskVulkanBuffer * gsk_vulkan_buffer_new_staging (GdkVulkanContext *context,
- gsize size);
-GskVulkanBuffer * gsk_vulkan_buffer_new_download (GdkVulkanContext *context,
- gsize size);
-void gsk_vulkan_buffer_free (GskVulkanBuffer *buffer);
-
-VkBuffer gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self);
-
-guchar * gsk_vulkan_buffer_map (GskVulkanBuffer *self);
-void gsk_vulkan_buffer_unmap (GskVulkanBuffer *self);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_BUFFER_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanclipprivate.h"
-
-#include "gskroundedrectprivate.h"
-
-void
-gsk_vulkan_clip_init_empty (GskVulkanClip *clip,
- const graphene_rect_t *rect)
-{
- clip->type = GSK_VULKAN_CLIP_NONE;
- gsk_rounded_rect_init_from_rect (&clip->rect, rect, 0);
-}
-
-static void
-gsk_vulkan_clip_init_copy (GskVulkanClip *self,
- const GskVulkanClip *src)
-{
- self->type = src->type;
- gsk_rounded_rect_init_copy (&self->rect, &src->rect);
-}
-
-gboolean
-gsk_vulkan_clip_intersect_rect (GskVulkanClip *dest,
- const GskVulkanClip *src,
- const graphene_rect_t *rect)
-{
- if (graphene_rect_contains_rect (rect, &src->rect.bounds))
- {
- gsk_vulkan_clip_init_copy (dest, src);
- return TRUE;
- }
- if (!graphene_rect_intersection (rect, &src->rect.bounds, NULL))
- {
- dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
- return TRUE;
- }
-
- switch (src->type)
- {
- case GSK_VULKAN_CLIP_ALL_CLIPPED:
- dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
- break;
-
- case GSK_VULKAN_CLIP_NONE:
- gsk_vulkan_clip_init_copy (dest, src);
- if (graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
- dest->type = GSK_VULKAN_CLIP_RECT;
- else
- dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
- break;
-
- case GSK_VULKAN_CLIP_RECT:
- gsk_vulkan_clip_init_copy (dest, src);
- if (!graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
- dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
- break;
-
- case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
- case GSK_VULKAN_CLIP_ROUNDED:
- if (gsk_rounded_rect_contains_rect (&src->rect, rect))
- {
- dest->type = GSK_VULKAN_CLIP_RECT;
- gsk_rounded_rect_init_from_rect (&dest->rect, rect, 0);
- }
- else
- {
- /* some points of rect are inside src's rounded rect,
- * some are outside. */
- /* XXX: If the 2 rects don't intersect on rounded corners,
- * we could actually compute a new clip here.
- */
- return FALSE;
- }
-
- default:
- g_assert_not_reached ();
- return FALSE;
- }
-
- return TRUE;
-}
-
-gboolean
-gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
- const GskVulkanClip *src,
- const GskRoundedRect *rounded)
-{
- if (gsk_rounded_rect_contains_rect (rounded, &src->rect.bounds))
- {
- gsk_vulkan_clip_init_copy (dest, src);
- return TRUE;
- }
- if (!graphene_rect_intersection (&rounded->bounds, &src->rect.bounds, NULL))
- {
- dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
- return TRUE;
- }
-
- switch (src->type)
- {
- case GSK_VULKAN_CLIP_ALL_CLIPPED:
- dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
- break;
-
- case GSK_VULKAN_CLIP_NONE:
- dest->type = gsk_rounded_rect_is_circular (&dest->rect) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
- gsk_rounded_rect_init_copy (&dest->rect, rounded);
- break;
-
- case GSK_VULKAN_CLIP_RECT:
- if (graphene_rect_contains_rect (&src->rect.bounds, &rounded->bounds))
- {
- dest->type = gsk_rounded_rect_is_circular (&dest->rect) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
- gsk_rounded_rect_init_copy (&dest->rect, rounded);
- return TRUE;
- }
- /* some points of rect are inside src's rounded rect,
- * some are outside. */
- /* XXX: If the 2 rects don't intersect on rounded corners,
- * we could actually compute a new clip here.
- */
- return FALSE;
-
- case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
- case GSK_VULKAN_CLIP_ROUNDED:
- /* XXX: improve */
- return FALSE;
-
- default:
- g_assert_not_reached ();
- return FALSE;
- }
-
- return TRUE;
-}
-
-gboolean
-gsk_vulkan_clip_transform (GskVulkanClip *dest,
- const GskVulkanClip *src,
- const graphene_matrix_t *transform,
- const graphene_rect_t *viewport)
-{
- switch (src->type)
- {
- default:
- g_assert_not_reached();
- return FALSE;
-
- case GSK_VULKAN_CLIP_ALL_CLIPPED:
- gsk_vulkan_clip_init_copy (dest, src);
- return TRUE;
-
- case GSK_VULKAN_CLIP_NONE:
- gsk_vulkan_clip_init_empty (dest, viewport);
- return TRUE;
-
- case GSK_VULKAN_CLIP_RECT:
- case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
- case GSK_VULKAN_CLIP_ROUNDED:
- /* FIXME: Handle 2D operations, in particular transform and scale */
- return FALSE;
- }
-}
-
-gboolean
-gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
- const graphene_rect_t *rect)
-{
- switch (self->type)
- {
- default:
- g_assert_not_reached();
- case GSK_VULKAN_CLIP_ALL_CLIPPED:
- return FALSE;
-
- case GSK_VULKAN_CLIP_NONE:
- return TRUE;
-
- case GSK_VULKAN_CLIP_RECT:
- return graphene_rect_contains_rect (&self->rect.bounds, rect);
-
- case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
- case GSK_VULKAN_CLIP_ROUNDED:
- return gsk_rounded_rect_contains_rect (&self->rect, rect);
- }
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_CLIP_PRIVATE_H__
-#define __GSK_VULKAN_CLIP_PRIVATE_H__
-
-#include <gdk/gdk.h>
-#include <graphene.h>
-#include <gsk/gskroundedrect.h>
-
-G_BEGIN_DECLS
-
-typedef enum {
- /* The whole area is clipped, no drawing is necessary.
- * This can't be handled by return values because for return
- * values we return if clips could even be computed.
- */
- GSK_VULKAN_CLIP_ALL_CLIPPED,
- /* No clipping is necessary, but the clip rect is set
- * to the actual bounds of the underlying framebuffer
- */
- GSK_VULKAN_CLIP_NONE,
- /* The clip is a rectangular area */
- GSK_VULKAN_CLIP_RECT,
- /* The clip is a rounded rectangle, and for every corner
- * corner.width == corner.height is true
- */
- GSK_VULKAN_CLIP_ROUNDED_CIRCULAR,
- /* The clip is a rounded rectangle */
- GSK_VULKAN_CLIP_ROUNDED
-} GskVulkanClipComplexity;
-
-typedef struct _GskVulkanClip GskVulkanClip;
-
-struct _GskVulkanClip
-{
- GskVulkanClipComplexity type;
- GskRoundedRect rect;
-};
-
-void gsk_vulkan_clip_init_empty (GskVulkanClip *clip,
- const graphene_rect_t *rect);
-
-gboolean gsk_vulkan_clip_intersect_rect (GskVulkanClip *dest,
- const GskVulkanClip *src,
- const graphene_rect_t *rect) G_GNUC_WARN_UNUSED_RESULT;
-gboolean gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
- const GskVulkanClip *src,
- const GskRoundedRect *rounded) G_GNUC_WARN_UNUSED_RESULT;
-gboolean gsk_vulkan_clip_transform (GskVulkanClip *dest,
- const GskVulkanClip *src,
- const graphene_matrix_t*transform,
- const graphene_rect_t *viewport) G_GNUC_WARN_UNUSED_RESULT;
-
-gboolean gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
- const graphene_rect_t *rect) G_GNUC_WARN_UNUSED_RESULT;
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_CLIP_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkancolorpipelineprivate.h"
-
-struct _GskVulkanColorPipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanColorInstance GskVulkanColorInstance;
-
-struct _GskVulkanColorInstance
-{
- float rect[4];
- float color[4];
-};
-
-G_DEFINE_TYPE (GskVulkanColorPipeline, gsk_vulkan_color_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_color_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanColorInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = 0,
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanColorInstance, color),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_color_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanColorPipeline *self = GSK_VULKAN_COLOR_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_color_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_color_pipeline_class_init (GskVulkanColorPipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_color_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_color_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_color_pipeline_init (GskVulkanColorPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_color_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_COLOR_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_color_pipeline_count_vertex_data (GskVulkanColorPipeline *pipeline)
-{
- return sizeof (GskVulkanColorInstance);
-}
-
-void
-gsk_vulkan_color_pipeline_collect_vertex_data (GskVulkanColorPipeline *pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const GdkRGBA *color)
-{
- GskVulkanColorInstance *instance = (GskVulkanColorInstance *) data;
-
- instance->rect[0] = rect->origin.x;
- instance->rect[1] = rect->origin.y;
- instance->rect[2] = rect->size.width;
- instance->rect[3] = rect->size.height;
- instance->color[0] = color->red;
- instance->color[1] = color->green;
- instance->color[2] = color->blue;
- instance->color[3] = color->alpha;
-}
-
-gsize
-gsk_vulkan_color_pipeline_draw (GskVulkanColorPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanColorPipelineLayout GskVulkanColorPipelineLayout;
-
-#define GSK_TYPE_VULKAN_COLOR_PIPELINE (gsk_vulkan_color_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanColorPipeline, gsk_vulkan_color_pipeline, GSK, VULKAN_COLOR_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_color_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_color_pipeline_count_vertex_data (GskVulkanColorPipeline *pipeline);
-void gsk_vulkan_color_pipeline_collect_vertex_data (GskVulkanColorPipeline *pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const GdkRGBA *color);
-gsize gsk_vulkan_color_pipeline_draw (GskVulkanColorPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkancolortextpipelineprivate.h"
-
-struct _GskVulkanColorTextPipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanColorTextInstance GskVulkanColorTextInstance;
-
-struct _GskVulkanColorTextInstance
-{
- float rect[4];
- float tex_rect[4];
-};
-
-G_DEFINE_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_color_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanColorTextInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, rect),
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, tex_rect),
- },
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_color_text_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanColorTextPipeline *self = GSK_VULKAN_COLOR_TEXT_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_color_text_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_color_text_pipeline_class_init (GskVulkanColorTextPipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_color_text_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_color_text_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_color_text_pipeline_init (GskVulkanColorTextPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_color_text_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE, context, layout, shader_name, render_pass,
- VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
-}
-
-gsize
-gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
- int num_instances)
-{
- return sizeof (GskVulkanColorTextInstance) * num_instances;
-}
-
-void
-gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
- guchar *data,
- GskVulkanRenderer *renderer,
- const graphene_rect_t *rect,
- PangoFont *font,
- guint total_glyphs,
- const PangoGlyphInfo *glyphs,
- float x,
- float y,
- guint start_glyph,
- guint num_glyphs,
- float scale)
-{
- GskVulkanColorTextInstance *instances = (GskVulkanColorTextInstance *) data;
- int i;
- int count = 0;
- int x_position = 0;
-
- for (i = 0; i < start_glyph; i++)
- x_position += glyphs[i].geometry.width;
-
- for (; i < total_glyphs && count < num_glyphs; i++)
- {
- const PangoGlyphInfo *gi = &glyphs[i];
-
- if (gi->glyph != PANGO_GLYPH_EMPTY)
- {
- double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
- double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
- GskVulkanColorTextInstance *instance = &instances[count];
- GskVulkanCachedGlyph *glyph;
-
- glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
-
- instance->tex_rect[0] = glyph->tx;
- instance->tex_rect[1] = glyph->ty;
- instance->tex_rect[2] = glyph->tw;
- instance->tex_rect[3] = glyph->th;
-
- instance->rect[0] = x + cx + glyph->draw_x;
- instance->rect[1] = y + cy + glyph->draw_y;
- instance->rect[2] = glyph->draw_width;
- instance->rect[3] = glyph->draw_height;
-
- count++;
- }
- x_position += gi->geometry.width;
- }
-}
-
-gsize
-gsk_vulkan_color_text_pipeline_draw (GskVulkanColorTextPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanrendererprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanColorTextPipelineLayout GskVulkanColorTextPipelineLayout;
-
-#define GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE (gsk_vulkan_color_text_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK, VULKAN_COLOR_TEXT_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_color_text_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
- int num_instances);
-void gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
- guchar *data,
- GskVulkanRenderer *renderer,
- const graphene_rect_t *rect,
- PangoFont *font,
- guint total_glyphs,
- const PangoGlyphInfo *glyphs,
- float x,
- float y,
- guint start_glyph,
- guint num_glyphs,
- float scale);
-gsize gsk_vulkan_color_text_pipeline_draw (GskVulkanColorTextPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkancommandpoolprivate.h"
-#include "gskvulkanpipelineprivate.h"
-
-struct _GskVulkanCommandPool
-{
- GdkVulkanContext *vulkan;
-
- VkCommandPool vk_command_pool;
-};
-
-GskVulkanCommandPool *
-gsk_vulkan_command_pool_new (GdkVulkanContext *context)
-{
- GskVulkanCommandPool *self;
-
- self = g_slice_new0 (GskVulkanCommandPool);
-
- self->vulkan = g_object_ref (context);
-
- GSK_VK_CHECK (vkCreateCommandPool, gdk_vulkan_context_get_device (context),
- &(const VkCommandPoolCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
- .queueFamilyIndex = gdk_vulkan_context_get_queue_family_index (self->vulkan),
- .flags = 0
- },
- NULL,
- &self->vk_command_pool);
-
- return self;
-}
-
-void
-gsk_vulkan_command_pool_free (GskVulkanCommandPool *self)
-{
- vkDestroyCommandPool (gdk_vulkan_context_get_device (self->vulkan),
- self->vk_command_pool,
- NULL);
-
- g_slice_free (GskVulkanCommandPool, self);
-}
-
-void
-gsk_vulkan_command_pool_reset (GskVulkanCommandPool *self)
-{
- GSK_VK_CHECK (vkResetCommandPool, gdk_vulkan_context_get_device (self->vulkan),
- self->vk_command_pool,
- 0);
-}
-
-VkCommandBuffer
-gsk_vulkan_command_pool_get_buffer (GskVulkanCommandPool *self)
-{
- VkCommandBuffer command_buffer;
-
- GSK_VK_CHECK (vkAllocateCommandBuffers, gdk_vulkan_context_get_device (self->vulkan),
- &(VkCommandBufferAllocateInfo) {
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
- .commandPool = self->vk_command_pool,
- .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
- .commandBufferCount = 1,
- },
- &command_buffer);
-
- GSK_VK_CHECK (vkBeginCommandBuffer, command_buffer,
- &(VkCommandBufferBeginInfo) {
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
- .flags = 0
- });
-
- return command_buffer;
-}
-
-void
-gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
- VkCommandBuffer command_buffer,
- gsize wait_semaphore_count,
- VkSemaphore *wait_semaphores,
- gsize signal_semaphore_count,
- VkSemaphore *signal_semaphores,
- VkFence fence)
-{
- VkPipelineStageFlags *wait_semaphore_flags = NULL;
-
- GSK_VK_CHECK (vkEndCommandBuffer, command_buffer);
-
- if (wait_semaphore_count > 0)
- {
- wait_semaphore_flags = alloca (sizeof (VkPipelineStageFlags) * wait_semaphore_count);
- for (int i = 0; i < wait_semaphore_count; i++)
- wait_semaphore_flags[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- }
-
- GSK_VK_CHECK (vkQueueSubmit, gdk_vulkan_context_get_queue (self->vulkan),
- 1,
- &(VkSubmitInfo) {
- .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
- .waitSemaphoreCount = wait_semaphore_count,
- .pWaitSemaphores = wait_semaphores,
- .pWaitDstStageMask = wait_semaphore_flags,
- .commandBufferCount = 1,
- .pCommandBuffers = (VkCommandBuffer[1]) {
- command_buffer
- },
- .signalSemaphoreCount = signal_semaphore_count,
- .pSignalSemaphores = signal_semaphores,
- },
- fence);
-}
-
+++ /dev/null
-#ifndef __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__
-#define __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanCommandPool GskVulkanCommandPool;
-
-GskVulkanCommandPool * gsk_vulkan_command_pool_new (GdkVulkanContext *context);
-void gsk_vulkan_command_pool_free (GskVulkanCommandPool *self);
-
-void gsk_vulkan_command_pool_reset (GskVulkanCommandPool *self);
-
-VkCommandBuffer gsk_vulkan_command_pool_get_buffer (GskVulkanCommandPool *self);
-void gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
- VkCommandBuffer buffer,
- gsize wait_semaphore_count,
- VkSemaphore *wait_semaphores,
- gsize signal_semaphores_count,
- VkSemaphore *signal_semaphores,
- VkFence fence);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkancrossfadepipelineprivate.h"
-
-struct _GskVulkanCrossFadePipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanCrossFadeInstance GskVulkanCrossFadeInstance;
-
-struct _GskVulkanCrossFadeInstance
-{
- float rect[4];
- float start_tex_rect[4];
- float end_tex_rect[4];
- float progress;
-};
-
-G_DEFINE_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_cross_fade_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanCrossFadeInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = 0,
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_rect),
- },
- {
- .location = 2,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_rect),
- },
- {
- .location = 3,
- .binding = 0,
- .format = VK_FORMAT_R32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, progress),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_cross_fade_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanCrossFadePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_cross_fade_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_cross_fade_pipeline_class_init (GskVulkanCrossFadePipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_cross_fade_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_cross_fade_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_cross_fade_pipeline_init (GskVulkanCrossFadePipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline)
-{
- return sizeof (GskVulkanCrossFadeInstance);
-}
-
-void
-gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
- guchar *data,
- const graphene_rect_t *bounds,
- const graphene_rect_t *start_tex_rect,
- const graphene_rect_t *end_tex_rect,
- double progress)
-{
- GskVulkanCrossFadeInstance *instance = (GskVulkanCrossFadeInstance *) data;
-
- instance->rect[0] = bounds->origin.x;
- instance->rect[1] = bounds->origin.y;
- instance->rect[2] = bounds->size.width;
- instance->rect[3] = bounds->size.height;
-
- instance->start_tex_rect[0] = start_tex_rect->origin.x;
- instance->start_tex_rect[1] = start_tex_rect->origin.y;
- instance->start_tex_rect[2] = start_tex_rect->size.width;
- instance->start_tex_rect[3] = start_tex_rect->size.height;
-
- instance->end_tex_rect[0] = end_tex_rect->origin.x;
- instance->end_tex_rect[1] = end_tex_rect->origin.y;
- instance->end_tex_rect[2] = end_tex_rect->size.width;
- instance->end_tex_rect[3] = end_tex_rect->size.height;
-
- instance->progress = progress;
-}
-
-gsize
-gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanCrossFadePipelineLayout GskVulkanCrossFadePipelineLayout;
-
-#define GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE (gsk_vulkan_cross_fade_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK, VULKAN_CROSS_FADE_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline);
-void gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
- guchar *data,
- const graphene_rect_t *bounds,
- const graphene_rect_t *start_bounds,
- const graphene_rect_t *end_bounds,
- double progress);
-gsize gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkaneffectpipelineprivate.h"
-
-struct _GskVulkanEffectPipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanEffectInstance GskVulkanEffectInstance;
-
-struct _GskVulkanEffectInstance
-{
- float rect[4];
- float tex_rect[4];
- float color_matrix[16];
- float color_offset[4];
-};
-
-G_DEFINE_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_effect_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanEffectInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = 0,
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, tex_rect),
- },
- {
- .location = 2,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix),
- },
- {
- .location = 3,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 4,
- },
- {
- .location = 4,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 8,
- },
- {
- .location = 5,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 12,
- },
- {
- .location = 6,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_offset),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_effect_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanEffectPipeline *self = GSK_VULKAN_EFFECT_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_effect_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_effect_pipeline_class_init (GskVulkanEffectPipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_effect_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_effect_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_effect_pipeline_init (GskVulkanEffectPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_effect_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_EFFECT_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline)
-{
- return sizeof (GskVulkanEffectInstance);
-}
-
-void
-gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const graphene_rect_t *tex_rect,
- const graphene_matrix_t *color_matrix,
- const graphene_vec4_t *color_offset)
-{
- GskVulkanEffectInstance *instance = (GskVulkanEffectInstance *) data;
-
- instance->rect[0] = rect->origin.x;
- instance->rect[1] = rect->origin.y;
- instance->rect[2] = rect->size.width;
- instance->rect[3] = rect->size.height;
- instance->tex_rect[0] = tex_rect->origin.x;
- instance->tex_rect[1] = tex_rect->origin.y;
- instance->tex_rect[2] = tex_rect->size.width;
- instance->tex_rect[3] = tex_rect->size.height;
- graphene_matrix_to_float (color_matrix, instance->color_matrix);
- graphene_vec4_to_float (color_offset, instance->color_offset);
-}
-
-gsize
-gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanEffectPipelineLayout GskVulkanEffectPipelineLayout;
-
-#define GSK_TYPE_VULKAN_EFFECT_PIPELINE (gsk_vulkan_effect_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK, VULKAN_EFFECT_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_effect_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline);
-void gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const graphene_rect_t *tex_rect,
- const graphene_matrix_t *color_matrix,
- const graphene_vec4_t *color_offset);
-gsize gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanglyphcacheprivate.h"
-
-#include "gskvulkanimageprivate.h"
-#include "gskdebugprivate.h"
-#include "gskprivate.h"
-
-#include <graphene.h>
-
-/* Parameters for our cache eviction strategy.
- *
- * Each cached glyph has an age that gets reset every time a cached glyph gets used.
- * Glyphs that have not been used for the MAX_AGE frames are considered old. We keep
- * count of the pixels of each atlas that are taken up by old glyphs. We check the
- * fraction of old pixels every CHECK_INTERVAL frames, and if it is above MAX_OLD, then
- * we drop the atlas an all the glyphs contained in it from the cache.
- */
-
-#define MAX_AGE 60
-#define CHECK_INTERVAL 10
-#define MAX_OLD 0.333
-
-
-typedef struct {
- GskVulkanImage *image;
- int width, height;
- int x, y, y0;
- int num_glyphs;
- GList *dirty_glyphs;
- guint old_pixels;
-} Atlas;
-
-struct _GskVulkanGlyphCache {
- GObject parent_instance;
-
- GdkVulkanContext *vulkan;
-
- GHashTable *hash_table;
- GPtrArray *atlases;
-
- guint64 timestamp;
-};
-
-struct _GskVulkanGlyphCacheClass {
- GObjectClass parent_class;
-};
-
-G_DEFINE_TYPE (GskVulkanGlyphCache, gsk_vulkan_glyph_cache, G_TYPE_OBJECT)
-
-static guint glyph_cache_hash (gconstpointer v);
-static gboolean glyph_cache_equal (gconstpointer v1,
- gconstpointer v2);
-static void glyph_cache_key_free (gpointer v);
-static void glyph_cache_value_free (gpointer v);
-static void dirty_glyph_free (gpointer v);
-
-static Atlas *
-create_atlas (GskVulkanGlyphCache *cache)
-{
- Atlas *atlas;
-
- atlas = g_new0 (Atlas, 1);
- atlas->width = 512;
- atlas->height = 512;
- atlas->y0 = 1;
- atlas->y = 1;
- atlas->x = 1;
- atlas->image = NULL;
- atlas->num_glyphs = 0;
- atlas->dirty_glyphs = NULL;
-
- return atlas;
-}
-
-static void
-free_atlas (gpointer v)
-{
- Atlas *atlas = v;
-
- g_clear_object (&atlas->image);
- g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
- g_free (atlas);
-}
-
-static void
-gsk_vulkan_glyph_cache_init (GskVulkanGlyphCache *cache)
-{
- cache->hash_table = g_hash_table_new_full (glyph_cache_hash, glyph_cache_equal,
- glyph_cache_key_free, glyph_cache_value_free);
- cache->atlases = g_ptr_array_new_with_free_func (free_atlas);
-}
-
-static void
-gsk_vulkan_glyph_cache_finalize (GObject *object)
-{
- GskVulkanGlyphCache *cache = GSK_VULKAN_GLYPH_CACHE (object);
-
- g_ptr_array_unref (cache->atlases);
- g_hash_table_unref (cache->hash_table);
-
- G_OBJECT_CLASS (gsk_vulkan_glyph_cache_parent_class)->finalize (object);
-}
-
-static void
-gsk_vulkan_glyph_cache_class_init (GskVulkanGlyphCacheClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = gsk_vulkan_glyph_cache_finalize;
-}
-
-typedef struct {
- PangoFont *font;
- PangoGlyph glyph;
- guint scale; /* times 1024 */
-} GlyphCacheKey;
-
-static gboolean
-glyph_cache_equal (gconstpointer v1, gconstpointer v2)
-{
- const GlyphCacheKey *key1 = v1;
- const GlyphCacheKey *key2 = v2;
-
- return key1->font == key2->font &&
- key1->glyph == key2->glyph &&
- key1->scale == key2->scale;
-}
-
-static guint
-glyph_cache_hash (gconstpointer v)
-{
- const GlyphCacheKey *key = v;
-
- return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ key->scale;
-}
-
-static void
-glyph_cache_key_free (gpointer v)
-{
- GlyphCacheKey *f = v;
-
- g_object_unref (f->font);
- g_free (f);
-}
-
-static void
-glyph_cache_value_free (gpointer v)
-{
- g_free (v);
-}
-
-typedef struct {
- GlyphCacheKey *key;
- GskVulkanCachedGlyph *value;
- cairo_surface_t *surface;
-} DirtyGlyph;
-
-static void
-dirty_glyph_free (gpointer v)
-{
- DirtyGlyph *glyph = v;
-
- if (glyph->surface)
- cairo_surface_destroy (glyph->surface);
- g_free (glyph);
-}
-
-static void
-add_to_cache (GskVulkanGlyphCache *cache,
- GlyphCacheKey *key,
- GskVulkanCachedGlyph *value)
-{
- Atlas *atlas;
- int i;
- DirtyGlyph *dirty;
- int width = value->draw_width * key->scale / 1024;
- int height = value->draw_height * key->scale / 1024;
-
- for (i = 0; i < cache->atlases->len; i++)
- {
- int x, y, y0;
-
- atlas = g_ptr_array_index (cache->atlases, i);
- x = atlas->x;
- y = atlas->y;
- y0 = atlas->y0;
-
- if (atlas->x + width + 1 >= atlas->width)
- {
- /* start a new row */
- y0 = y + 1;
- x = 1;
- }
-
- if (y0 + height + 1 >= atlas->height)
- continue;
-
- atlas->y0 = y0;
- atlas->x = x;
- atlas->y = y;
- break;
- }
-
- if (i == cache->atlases->len)
- {
- atlas = create_atlas (cache);
- g_ptr_array_add (cache->atlases, atlas);
- }
-
- value->tx = (float)atlas->x / atlas->width;
- value->ty = (float)atlas->y0 / atlas->height;
- value->tw = (float)width / atlas->width;
- value->th = (float)height / atlas->height;
-
- value->texture_index = i;
-
- dirty = g_new (DirtyGlyph, 1);
- dirty->key = key;
- dirty->value = value;
- atlas->dirty_glyphs = g_list_prepend (atlas->dirty_glyphs, dirty);
-
- atlas->x = atlas->x + width + 1;
- atlas->y = MAX (atlas->y, atlas->y0 + height + 1);
-
- atlas->num_glyphs++;
-
-#ifdef G_ENABLE_DEBUG
- if (GSK_DEBUG_CHECK(GLYPH_CACHE))
- {
- g_print ("Glyph cache:\n");
- for (i = 0; i < cache->atlases->len; i++)
- {
- atlas = g_ptr_array_index (cache->atlases, i);
- g_print ("\tAtlas %d (%dx%d): %d glyphs (%d dirty), %.2g%% old pixels, filled to %d, %d / %d\n",
- i, atlas->width, atlas->height,
- atlas->num_glyphs, g_list_length (atlas->dirty_glyphs),
- 100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height),
- atlas->x, atlas->y0, atlas->y);
- }
- }
-#endif
-}
-
-static void
-render_glyph (Atlas *atlas,
- DirtyGlyph *glyph,
- GskImageRegion *region)
-{
- GlyphCacheKey *key = glyph->key;
- GskVulkanCachedGlyph *value = glyph->value;
- cairo_surface_t *surface;
- cairo_t *cr;
- PangoGlyphString glyphs;
- PangoGlyphInfo gi;
-
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- value->draw_width * key->scale / 1024,
- value->draw_height * key->scale / 1024);
- cairo_surface_set_device_scale (surface, key->scale / 1024.0, key->scale / 1024.0);
-
- cr = cairo_create (surface);
- cairo_set_source_rgba (cr, 1, 1, 1, 1);
-
- gi.glyph = key->glyph;
- gi.geometry.width = value->draw_width * 1024;
- if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
- gi.geometry.x_offset = 0;
- else
- gi.geometry.x_offset = - value->draw_x * 1024;
- gi.geometry.y_offset = - value->draw_y * 1024;
-
- glyphs.num_glyphs = 1;
- glyphs.glyphs = &gi;
-
- pango_cairo_show_glyph_string (cr, key->font, &glyphs);
-
- cairo_destroy (cr);
-
- glyph->surface = surface;
-
- region->data = cairo_image_surface_get_data (surface);
- region->width = cairo_image_surface_get_width (surface);
- region->height = cairo_image_surface_get_height (surface);
- region->stride = cairo_image_surface_get_stride (surface);
- region->x = (gsize)(value->tx * atlas->width);
- region->y = (gsize)(value->ty * atlas->height);
-}
-
-static void
-upload_dirty_glyphs (Atlas *atlas,
- GskVulkanUploader *uploader)
-{
- GList *l;
- guint num_regions;
- GskImageRegion *regions;
- int i;
-
- num_regions = g_list_length (atlas->dirty_glyphs);
- regions = alloca (sizeof (GskImageRegion) * num_regions);
-
- for (l = atlas->dirty_glyphs, i = 0; l; l = l->next, i++)
- render_glyph (atlas, (DirtyGlyph *)l->data, ®ions[i]);
-
- GSK_NOTE (GLYPH_CACHE,
- g_print ("uploading %d glyphs to cache\n", num_regions));
-
- gsk_vulkan_image_upload_regions (atlas->image, uploader, num_regions, regions);
-
- g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
- atlas->dirty_glyphs = NULL;
-}
-
-GskVulkanGlyphCache *
-gsk_vulkan_glyph_cache_new (GdkVulkanContext *vulkan)
-{
- GskVulkanGlyphCache *cache;
-
- cache = GSK_VULKAN_GLYPH_CACHE (g_object_new (GSK_TYPE_VULKAN_GLYPH_CACHE, NULL));
- cache->vulkan = vulkan;
- g_ptr_array_add (cache->atlases, create_atlas (cache));
-
- return cache;
-}
-
-GskVulkanCachedGlyph *
-gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
- gboolean create,
- PangoFont *font,
- PangoGlyph glyph,
- float scale)
-{
- GlyphCacheKey lookup_key;
- GskVulkanCachedGlyph *value;
-
- lookup_key.font = font;
- lookup_key.glyph = glyph;
- lookup_key.scale = (guint)(scale * 1024);
-
- value = g_hash_table_lookup (cache->hash_table, &lookup_key);
-
- if (value)
- {
- if (cache->timestamp - value->timestamp >= MAX_AGE)
- {
- Atlas *atlas = g_ptr_array_index (cache->atlases, value->texture_index);
-
- atlas->old_pixels -= value->draw_width * value->draw_height;
- value->timestamp = cache->timestamp;
- }
- }
-
- if (create && value == NULL)
- {
- GlyphCacheKey *key;
- PangoRectangle ink_rect;
-
- key = g_new (GlyphCacheKey, 1);
- value = g_new0 (GskVulkanCachedGlyph, 1);
-
- pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
- pango_extents_to_pixels (&ink_rect, NULL);
-
- value->draw_x = ink_rect.x;
- value->draw_y = ink_rect.y;
- value->draw_width = ink_rect.width;
- value->draw_height = ink_rect.height;
- value->timestamp = cache->timestamp;
-
- key->font = g_object_ref (font);
- key->glyph = glyph;
- key->scale = (guint)(scale * 1024);
-
- if (ink_rect.width > 0 && ink_rect.height > 0)
- add_to_cache (cache, key, value);
-
- g_hash_table_insert (cache->hash_table, key, value);
- }
-
- return value;
-}
-
-GskVulkanImage *
-gsk_vulkan_glyph_cache_get_glyph_image (GskVulkanGlyphCache *cache,
- GskVulkanUploader *uploader,
- guint index)
-{
- Atlas *atlas;
-
- g_return_val_if_fail (index < cache->atlases->len, NULL);
-
- atlas = g_ptr_array_index (cache->atlases, index);
-
- if (atlas->image == NULL)
- atlas->image = gsk_vulkan_image_new_for_atlas (cache->vulkan, atlas->width, atlas->height);
-
- if (atlas->dirty_glyphs)
- upload_dirty_glyphs (atlas, uploader);
-
- return atlas->image;
-}
-
-void
-gsk_vulkan_glyph_cache_begin_frame (GskVulkanGlyphCache *cache)
-{
- int i, j;
- guint *drops;
- guint *shifts;
- guint len;
- GHashTableIter iter;
- GlyphCacheKey *key;
- GskVulkanCachedGlyph *value;
- guint dropped = 0;
-
- cache->timestamp++;
-
- if (cache->timestamp % CHECK_INTERVAL != 0)
- return;
-
- len = cache->atlases->len;
-
- /* look for glyphs that have grown old since last time */
- g_hash_table_iter_init (&iter, cache->hash_table);
- while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
- {
- guint age;
-
- age = cache->timestamp - value->timestamp;
- if (MAX_AGE <= age && age < MAX_AGE + CHECK_INTERVAL)
- {
- Atlas *atlas = g_ptr_array_index (cache->atlases, value->texture_index);
- atlas->old_pixels += value->draw_width * value->draw_height;
- }
- }
-
- drops = g_alloca (sizeof (guint) * len);
- shifts = g_alloca (sizeof (guint) * len);
-
- for (i = 0; i < len; i++)
- {
- drops[i] = 0;
- shifts[i] = i;
- }
-
- /* look for atlases to drop, and create a mapping of updated texture indices */
- for (i = cache->atlases->len - 1; i >= 0; i--)
- {
- Atlas *atlas = g_ptr_array_index (cache->atlases, i);
-
- if (atlas->old_pixels > MAX_OLD * atlas->width * atlas->height)
- {
- GSK_NOTE(GLYPH_CACHE,
- g_print ("Dropping atlas %d (%g.2%% old)\n", i, 100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height)));
- g_ptr_array_remove_index (cache->atlases, i);
-
- drops[i] = 1;
- for (j = i; j + 1 < len; j++)
- shifts[j + 1] = shifts[j];
- }
- }
-
- /* no atlas dropped, we're done */
- if (len == cache->atlases->len)
- return;
-
- /* purge glyphs and update texture indices */
- g_hash_table_iter_init (&iter, cache->hash_table);
-
- while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
- {
- if (drops[value->texture_index])
- {
- dropped++;
- g_hash_table_iter_remove (&iter);
- }
- else
- {
- value->texture_index = shifts[value->texture_index];
- }
- }
-
- GSK_NOTE(GLYPH_CACHE, g_print ("Dropped %d glyphs\n", dropped));
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__
-#define __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__
-
-#include <pango/pango.h>
-#include "gskvulkanrendererprivate.h"
-#include "gskvulkanimageprivate.h"
-
-G_BEGIN_DECLS
-
-#define GSK_TYPE_VULKAN_GLYPH_CACHE (gsk_vulkan_glyph_cache_get_type ())
-
-G_DECLARE_FINAL_TYPE(GskVulkanGlyphCache, gsk_vulkan_glyph_cache, GSK, VULKAN_GLYPH_CACHE, GObject)
-
-GskVulkanGlyphCache *gsk_vulkan_glyph_cache_new (GdkVulkanContext *vulkan);
-
-GskVulkanImage * gsk_vulkan_glyph_cache_get_glyph_image (GskVulkanGlyphCache *cache,
- GskVulkanUploader *uploader,
- guint index);
-
-GskVulkanCachedGlyph *gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
- gboolean create,
- PangoFont *font,
- PangoGlyph glyph,
- float scale);
-
-void gsk_vulkan_glyph_cache_begin_frame (GskVulkanGlyphCache *cache);
-
-#endif /* __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanimageprivate.h"
-
-#include "gskvulkanbufferprivate.h"
-#include "gskvulkanmemoryprivate.h"
-#include "gskvulkanpipelineprivate.h"
-
-#include <string.h>
-
-struct _GskVulkanUploader
-{
- GdkVulkanContext *vulkan;
-
- GskVulkanCommandPool *command_pool;
-
- GArray *before_buffer_barriers;
- GArray *before_image_barriers;
- VkCommandBuffer copy_buffer;
- GArray *after_buffer_barriers;
- GArray *after_image_barriers;
-
- GSList *staging_image_free_list;
- GSList *staging_buffer_free_list;
-};
-
-struct _GskVulkanImage
-{
- GObject parent_instance;
-
- GdkVulkanContext *vulkan;
-
- gsize width;
- gsize height;
- VkImageUsageFlags vk_usage;
- VkImage vk_image;
- VkImageView vk_image_view;
- VkImageLayout vk_image_layout;
- VkAccessFlags vk_access;
-
- GskVulkanMemory *memory;
-};
-
-G_DEFINE_TYPE (GskVulkanImage, gsk_vulkan_image, G_TYPE_OBJECT)
-
-GskVulkanUploader *
-gsk_vulkan_uploader_new (GdkVulkanContext *context,
- GskVulkanCommandPool *command_pool)
-{
- GskVulkanUploader *self;
-
- self = g_slice_new0 (GskVulkanUploader);
-
- self->vulkan = g_object_ref (context);
- self->command_pool = command_pool;
-
- self->before_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
- self->after_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
-
- self->before_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
- self->after_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
-
- return self;
-}
-
-void
-gsk_vulkan_uploader_free (GskVulkanUploader *self)
-{
- gsk_vulkan_uploader_reset (self);
-
- g_array_unref (self->after_buffer_barriers);
- g_array_unref (self->before_buffer_barriers);
- g_array_unref (self->after_image_barriers);
- g_array_unref (self->before_image_barriers);
-
- g_object_unref (self->vulkan);
-
- g_slice_free (GskVulkanUploader, self);
-}
-
-static void
-gsk_vulkan_uploader_add_image_barrier (GskVulkanUploader *self,
- gboolean after,
- GskVulkanImage *image,
- VkImageLayout new_layout,
- VkAccessFlags new_access)
-{
- GArray *array;
- VkImageMemoryBarrier barrier = {
- .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
- .srcAccessMask = image->vk_access,
- .dstAccessMask = new_access,
- .oldLayout = image->vk_image_layout,
- .newLayout = new_layout,
- .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .image = image->vk_image,
- .subresourceRange = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .baseMipLevel = 0,
- .levelCount = 1,
- .baseArrayLayer = 0,
- .layerCount = 1
- }
- };
-
- if (after)
- array = self->after_image_barriers;
- else
- array = self->before_image_barriers;
-
- g_array_append_val (array, barrier);
-
- image->vk_image_layout = new_layout;
- image->vk_access = new_access;
-}
-
-static void
-gsk_vulkan_uploader_add_buffer_barrier (GskVulkanUploader *self,
- gboolean after,
- const VkBufferMemoryBarrier *barrier)
-{
- GArray *array;
-
- if (after)
- array = self->after_buffer_barriers;
- else
- array = self->before_buffer_barriers;
-
- g_array_append_val (array, *barrier);
-}
-
-static VkCommandBuffer
-gsk_vulkan_uploader_get_copy_buffer (GskVulkanUploader *self)
-{
- if (self->copy_buffer == VK_NULL_HANDLE)
- self->copy_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
-
- return self->copy_buffer;
-}
-
-void
-gsk_vulkan_uploader_upload (GskVulkanUploader *self)
-{
- if (self->before_buffer_barriers->len > 0 || self->before_image_barriers->len > 0)
- {
- VkCommandBuffer command_buffer;
-
- command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
- vkCmdPipelineBarrier (command_buffer,
- VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
- VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
- 0,
- 0, NULL,
- self->before_buffer_barriers->len, (VkBufferMemoryBarrier *) self->before_buffer_barriers->data,
- self->before_image_barriers->len, (VkImageMemoryBarrier *) self->before_image_barriers->data);
- gsk_vulkan_command_pool_submit_buffer (self->command_pool, command_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
- g_array_set_size (self->before_buffer_barriers, 0);
- g_array_set_size (self->before_image_barriers, 0);
- }
-
- /* append these to existing buffer */
- if (self->after_buffer_barriers->len > 0 || self->after_image_barriers->len > 0)
- {
- VkCommandBuffer command_buffer = gsk_vulkan_uploader_get_copy_buffer (self);
- vkCmdPipelineBarrier (command_buffer,
- VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
- 0,
- 0, NULL,
- self->after_buffer_barriers->len, (VkBufferMemoryBarrier *) self->after_buffer_barriers->data,
- self->after_image_barriers->len, (VkImageMemoryBarrier *) self->after_image_barriers->data);
- g_array_set_size (self->after_buffer_barriers, 0);
- g_array_set_size (self->after_image_barriers, 0);
- }
-
- if (self->copy_buffer != VK_NULL_HANDLE)
- {
- gsk_vulkan_command_pool_submit_buffer (self->command_pool, self->copy_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
- self->copy_buffer = VK_NULL_HANDLE;
- }
-}
-
-void
-gsk_vulkan_uploader_reset (GskVulkanUploader *self)
-{
- g_array_set_size (self->before_image_barriers, 0);
- self->copy_buffer = VK_NULL_HANDLE;
- g_array_set_size (self->after_image_barriers, 0);
-
- g_slist_free_full (self->staging_image_free_list, g_object_unref);
- self->staging_image_free_list = NULL;
- g_slist_free_full (self->staging_buffer_free_list, (GDestroyNotify) gsk_vulkan_buffer_free);
- self->staging_buffer_free_list = NULL;
-}
-
-static GskVulkanImage *
-gsk_vulkan_image_new (GdkVulkanContext *context,
- gsize width,
- gsize height,
- VkImageTiling tiling,
- VkImageUsageFlags usage,
- VkImageLayout layout,
- VkAccessFlags access,
- VkMemoryPropertyFlags memory)
-{
- VkMemoryRequirements requirements;
- GskVulkanImage *self;
-
- self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
-
- self->vulkan = g_object_ref (context);
- self->width = width;
- self->height = height;
- self->vk_usage = usage;
- self->vk_image_layout = layout;
- self->vk_access = access;
-
- GSK_VK_CHECK (vkCreateImage, gdk_vulkan_context_get_device (context),
- &(VkImageCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
- .flags = 0,
- .imageType = VK_IMAGE_TYPE_2D,
- .format = VK_FORMAT_B8G8R8A8_UNORM,
- .extent = { width, height, 1 },
- .mipLevels = 1,
- .arrayLayers = 1,
- .samples = VK_SAMPLE_COUNT_1_BIT,
- .tiling = tiling,
- .usage = usage,
- .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
- .initialLayout = self->vk_image_layout,
- },
- NULL,
- &self->vk_image);
-
- vkGetImageMemoryRequirements (gdk_vulkan_context_get_device (context),
- self->vk_image,
- &requirements);
-
- self->memory = gsk_vulkan_memory_new (context,
- requirements.memoryTypeBits,
- memory,
- requirements.size);
-
- GSK_VK_CHECK (vkBindImageMemory, gdk_vulkan_context_get_device (context),
- self->vk_image,
- gsk_vulkan_memory_get_device_memory (self->memory),
- 0);
- return self;
-}
-
-static void
-gsk_vulkan_image_upload_data (GskVulkanImage *self,
- guchar *data,
- gsize width,
- gsize height,
- gsize data_stride)
-{
- VkImageSubresource image_res;
- VkSubresourceLayout image_layout;
- gsize mem_stride;
- guchar *mem;
-
- image_res.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- image_res.mipLevel = 0;
- image_res.arrayLayer = 0;
-
- mem_stride = width * 4;
- vkGetImageSubresourceLayout (gdk_vulkan_context_get_device (self->vulkan),
- self->vk_image, &image_res, &image_layout);
-
- mem = gsk_vulkan_memory_map (self->memory) + image_layout.offset;
-
- if (image_layout.rowPitch == width * 4 && data_stride == mem_stride)
- {
- memcpy (mem, data, data_stride * height);
- }
- else
- {
- for (gsize i = 0; i < height; i++)
- {
- memcpy (mem + i * image_layout.rowPitch, data + i * data_stride, width * 4);
- }
- }
-
- gsk_vulkan_memory_unmap (self->memory);
-}
-
-static void
-gsk_vulkan_image_ensure_view (GskVulkanImage *self,
- VkFormat format)
-{
- if (self->vk_image_view == VK_NULL_HANDLE)
- GSK_VK_CHECK (vkCreateImageView, gdk_vulkan_context_get_device (self->vulkan),
- &(VkImageViewCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
- .image = self->vk_image,
- .viewType = VK_IMAGE_VIEW_TYPE_2D,
- .format = format,
- .components = {
- .r = VK_COMPONENT_SWIZZLE_R,
- .g = VK_COMPONENT_SWIZZLE_G,
- .b = VK_COMPONENT_SWIZZLE_B,
- .a = VK_COMPONENT_SWIZZLE_A,
- },
- .subresourceRange = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .baseMipLevel = 0,
- .levelCount = 1,
- .baseArrayLayer = 0,
- .layerCount = 1,
- },
- },
- NULL,
- &self->vk_image_view);
-}
-
-static GskVulkanImage *
-gsk_vulkan_image_new_from_data_via_staging_buffer (GskVulkanUploader *uploader,
- guchar *data,
- gsize width,
- gsize height,
- gsize stride)
-{
- GskVulkanImage *self;
- GskVulkanBuffer *staging;
- gsize buffer_size = width * height * 4;
- guchar *mem;
-
- staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, buffer_size);
- mem = gsk_vulkan_buffer_map (staging);
-
- if (stride == width * 4)
- {
- memcpy (mem, data, stride * height);
- }
- else
- {
- for (gsize i = 0; i < height; i++)
- {
- memcpy (mem + i * width * 4, data + i * stride, width * 4);
- }
- }
-
- gsk_vulkan_buffer_unmap (staging);
-
- gsk_vulkan_uploader_add_buffer_barrier (uploader,
- FALSE,
- &(VkBufferMemoryBarrier) {
- .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
- .srcAccessMask = VK_ACCESS_HOST_WRITE_BIT,
- .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
- .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .buffer = gsk_vulkan_buffer_get_buffer(staging),
- .offset = 0,
- .size = buffer_size,
- });
-
- self = gsk_vulkan_image_new (uploader->vulkan,
- width,
- height,
- VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_TRANSFER_DST_BIT |
- VK_IMAGE_USAGE_SAMPLED_BIT,
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_ACCESS_TRANSFER_WRITE_BIT,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
- gsk_vulkan_uploader_add_image_barrier (uploader,
- FALSE,
- self,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_ACCESS_TRANSFER_WRITE_BIT);
-
- vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
- gsk_vulkan_buffer_get_buffer (staging),
- self->vk_image,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- (VkBufferImageCopy[1]) {
- {
- .bufferOffset = 0,
- .imageSubresource = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .mipLevel = 0,
- .baseArrayLayer = 0,
- .layerCount = 1
- },
- .imageOffset = { 0, 0, 0 },
- .imageExtent = {
- .width = width,
- .height = height,
- .depth = 1
- }
- }
- });
-
- gsk_vulkan_uploader_add_image_barrier (uploader,
- TRUE,
- self,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
- VK_ACCESS_SHADER_READ_BIT);
-
- uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, staging);
-
- gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
- return self;
-}
-
-static GskVulkanImage *
-gsk_vulkan_image_new_from_data_via_staging_image (GskVulkanUploader *uploader,
- guchar *data,
- gsize width,
- gsize height,
- gsize stride)
-{
- GskVulkanImage *self, *staging;
-
- staging = gsk_vulkan_image_new (uploader->vulkan,
- width,
- height,
- VK_IMAGE_TILING_LINEAR,
- VK_IMAGE_USAGE_TRANSFER_DST_BIT |
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
- VK_IMAGE_LAYOUT_PREINITIALIZED,
- VK_ACCESS_TRANSFER_WRITE_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
-
- gsk_vulkan_image_upload_data (staging, data, width, height, stride);
-
- self = gsk_vulkan_image_new (uploader->vulkan,
- width,
- height,
- VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_TRANSFER_DST_BIT |
- VK_IMAGE_USAGE_SAMPLED_BIT,
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_ACCESS_TRANSFER_WRITE_BIT,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
- gsk_vulkan_uploader_add_image_barrier (uploader,
- FALSE,
- staging,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_ACCESS_TRANSFER_READ_BIT);
-
- gsk_vulkan_uploader_add_image_barrier (uploader,
- FALSE,
- self,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_ACCESS_TRANSFER_WRITE_BIT);
-
- vkCmdCopyImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
- staging->vk_image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- self->vk_image,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- &(VkImageCopy) {
- .srcSubresource = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .mipLevel = 0,
- .baseArrayLayer = 0,
- .layerCount = 1
- },
- .srcOffset = { 0, 0, 0 },
- .dstSubresource = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .mipLevel = 0,
- .baseArrayLayer = 0,
- .layerCount = 1
- },
- .dstOffset = { 0, 0, 0 },
- .extent = {
- .width = width,
- .height = height,
- .depth = 1
- }
- });
-
- gsk_vulkan_uploader_add_image_barrier (uploader,
- TRUE,
- self,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
- VK_ACCESS_SHADER_READ_BIT);
-
- uploader->staging_image_free_list = g_slist_prepend (uploader->staging_image_free_list, staging);
-
- gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
- return self;
-}
-
-static GskVulkanImage *
-gsk_vulkan_image_new_from_data_directly (GskVulkanUploader *uploader,
- guchar *data,
- gsize width,
- gsize height,
- gsize stride)
-{
- GskVulkanImage *self;
-
- self = gsk_vulkan_image_new (uploader->vulkan,
- width,
- height,
- VK_IMAGE_TILING_LINEAR,
- VK_IMAGE_USAGE_SAMPLED_BIT,
- VK_IMAGE_LAYOUT_PREINITIALIZED,
- VK_ACCESS_HOST_WRITE_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
-
- gsk_vulkan_image_upload_data (self, data, width, height, stride);
-
- gsk_vulkan_uploader_add_image_barrier (uploader,
- TRUE,
- self,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
- VK_ACCESS_SHADER_READ_BIT);
-
- gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
- return self;
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_from_data (GskVulkanUploader *uploader,
- guchar *data,
- gsize width,
- gsize height,
- gsize stride)
-{
- if (GSK_RENDER_MODE_CHECK (STAGING_BUFFER))
- return gsk_vulkan_image_new_from_data_via_staging_buffer (uploader, data, width, height, stride);
- if (GSK_RENDER_MODE_CHECK (STAGING_IMAGE))
- return gsk_vulkan_image_new_from_data_via_staging_image (uploader, data, width, height, stride);
- else
- return gsk_vulkan_image_new_from_data_directly (uploader, data, width, height, stride);
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
- VkImage image,
- VkFormat format,
- gsize width,
- gsize height)
-{
- GskVulkanImage *self;
-
- self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
-
- self->vulkan = g_object_ref (context);
- self->width = width;
- self->height = height;
- self->vk_image = image;
-
- gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
- return self;
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
- gsize width,
- gsize height)
-{
- GskVulkanImage *self;
-
-
- self = gsk_vulkan_image_new (context,
- width,
- height,
- VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
- gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
- return self;
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
- gsize width,
- gsize height)
-{
- GskVulkanImage *self;
-
- self = gsk_vulkan_image_new (context,
- width,
- height,
- VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
- VK_IMAGE_LAYOUT_UNDEFINED,
- 0,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
- gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
- return self;
-}
-
-GskVulkanImage *
-gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
- gsize width,
- gsize height)
-{
- GskVulkanImage *self;
-
- self = gsk_vulkan_image_new (context,
- width,
- height,
- VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
- VK_IMAGE_USAGE_SAMPLED_BIT |
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
- VK_IMAGE_LAYOUT_UNDEFINED,
- 0,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
- gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-
- return self;
-}
-
-GdkTexture *
-gsk_vulkan_image_download (GskVulkanImage *self,
- GskVulkanUploader *uploader)
-{
- GskVulkanBuffer *buffer;
- GdkTexture *texture;
- guchar *mem;
-
- gsk_vulkan_uploader_add_image_barrier (uploader,
- FALSE,
- self,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_ACCESS_TRANSFER_READ_BIT);
-
- buffer = gsk_vulkan_buffer_new_download (self->vulkan, self->width * self->height * 4);
-
- vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader),
- self->vk_image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- gsk_vulkan_buffer_get_buffer (buffer),
- 1,
- (VkBufferImageCopy[1]) {
- {
- .bufferOffset = 0,
- .imageSubresource = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .mipLevel = 0,
- .baseArrayLayer = 0,
- .layerCount = 1
- },
- .imageOffset = { 0, 0, 0 },
- .imageExtent = {
- .width = self->width,
- .height = self->height,
- .depth = 1
- }
- }
- });
-
- gsk_vulkan_uploader_upload (uploader);
-
- GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
-
- mem = gsk_vulkan_buffer_map (buffer);
- texture = gdk_texture_new_for_data (mem, self->width, self->height, self->width * 4);
- gsk_vulkan_buffer_unmap (buffer);
- gsk_vulkan_buffer_free (buffer);
-
- return texture;
-}
-
-void
-gsk_vulkan_image_upload_regions (GskVulkanImage *self,
- GskVulkanUploader *uploader,
- guint num_regions,
- GskImageRegion *regions)
-{
- GskVulkanBuffer *staging;
- guchar *mem;
- guchar *m;
- gsize size;
- gsize offset;
- VkBufferImageCopy *bufferImageCopy;
-
- size = 0;
- for (int i = 0; i < num_regions; i++)
- size += regions[i].width * regions[i].height * 4;
-
- staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, size);
- mem = gsk_vulkan_buffer_map (staging);
-
- bufferImageCopy = alloca (sizeof (VkBufferImageCopy) * num_regions);
- memset (bufferImageCopy, 0, sizeof (VkBufferImageCopy) * num_regions);
-
- offset = 0;
- for (int i = 0; i < num_regions; i++)
- {
- m = mem + offset;
- if (regions[i].stride == regions[i].width * 4)
- {
- memcpy (m, regions[i].data, regions[i].stride * regions[i].height);
- }
- else
- {
- for (gsize r = 0; r < regions[i].height; i++)
- memcpy (m + r * regions[i].width * 4, regions[i].data + r * regions[i].stride, regions[i].width * 4);
- }
-
- bufferImageCopy[i].bufferOffset = offset;
- bufferImageCopy[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- bufferImageCopy[i].imageSubresource.mipLevel = 0;
- bufferImageCopy[i].imageSubresource.baseArrayLayer = 0;
- bufferImageCopy[i].imageSubresource.layerCount = 1;
- bufferImageCopy[i].imageOffset.x = regions[i].x;
- bufferImageCopy[i].imageOffset.y = regions[i].y;
- bufferImageCopy[i].imageOffset.z = 0;
- bufferImageCopy[i].imageExtent.width = regions[i].width;
- bufferImageCopy[i].imageExtent.height = regions[i].height;
- bufferImageCopy[i].imageExtent.depth = 1;
-
- offset += regions[i].width * regions[i].height * 4;
- }
-
- gsk_vulkan_buffer_unmap (staging);
-
- gsk_vulkan_uploader_add_image_barrier (uploader,
- FALSE,
- self,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_ACCESS_TRANSFER_WRITE_BIT);
-
- vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
- gsk_vulkan_buffer_get_buffer (staging),
- self->vk_image,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- num_regions,
- bufferImageCopy);
-
- gsk_vulkan_uploader_add_image_barrier (uploader,
- TRUE,
- self,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
- VK_ACCESS_SHADER_READ_BIT);
-
- uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, staging);
-
- gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
-}
-
-static void
-gsk_vulkan_image_finalize (GObject *object)
-{
- GskVulkanImage *self = GSK_VULKAN_IMAGE (object);
-
- if (self->vk_image_view != VK_NULL_HANDLE)
- {
- vkDestroyImageView (gdk_vulkan_context_get_device (self->vulkan),
- self->vk_image_view,
- NULL);
- }
-
- /* memory is NULL for for_swapchain() images, where we don't own
- * the VkImage */
- if (self->memory)
- {
- vkDestroyImage (gdk_vulkan_context_get_device (self->vulkan),
- self->vk_image,
- NULL);
-
- gsk_vulkan_memory_free (self->memory);
- }
-
- g_object_unref (self->vulkan);
-
- G_OBJECT_CLASS (gsk_vulkan_image_parent_class)->finalize (object);
-}
-
-static void
-gsk_vulkan_image_class_init (GskVulkanImageClass *klass)
-{
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_image_finalize;
-}
-
-static void
-gsk_vulkan_image_init (GskVulkanImage *self)
-{
-}
-
-gsize
-gsk_vulkan_image_get_width (GskVulkanImage *self)
-{
- return self->width;
-}
-
-gsize
-gsk_vulkan_image_get_height (GskVulkanImage *self)
-{
- return self->height;
-}
-
-VkImage
-gsk_vulkan_image_get_image (GskVulkanImage *self)
-{
- return self->vk_image;
-}
-
-VkImageView
-gsk_vulkan_image_get_image_view (GskVulkanImage *self)
-{
- return self->vk_image_view;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_IMAGE_PRIVATE_H__
-#define __GSK_VULKAN_IMAGE_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-#include "gsk/gskvulkancommandpoolprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanUploader GskVulkanUploader;
-
-#define GSK_TYPE_VULKAN_IMAGE (gsk_vulkan_image_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanImage, gsk_vulkan_image, GSK, VULKAN_IMAGE, GObject)
-
-GskVulkanUploader * gsk_vulkan_uploader_new (GdkVulkanContext *context,
- GskVulkanCommandPool *command_pool);
-void gsk_vulkan_uploader_free (GskVulkanUploader *self);
-
-void gsk_vulkan_uploader_reset (GskVulkanUploader *self);
-void gsk_vulkan_uploader_upload (GskVulkanUploader *self);
-
-GskVulkanImage * gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
- VkImage image,
- VkFormat format,
- gsize width,
- gsize height);
-GskVulkanImage * gsk_vulkan_image_new_from_data (GskVulkanUploader *uploader,
- guchar *data,
- gsize width,
- gsize height,
- gsize stride);
-
-typedef struct {
- guchar *data;
- gsize width;
- gsize height;
- gsize stride;
- gsize x;
- gsize y;
-} GskImageRegion;
-
-void gsk_vulkan_image_upload_regions (GskVulkanImage *image,
- GskVulkanUploader *uploader,
- guint num_regions,
- GskImageRegion *regions);
-GskVulkanImage * gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
- gsize width,
- gsize height);
-GskVulkanImage * gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
- gsize width,
- gsize height);
-GskVulkanImage * gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
- gsize width,
- gsize height);
-
-GdkTexture * gsk_vulkan_image_download (GskVulkanImage *self,
- GskVulkanUploader *uploader);
-
-gsize gsk_vulkan_image_get_width (GskVulkanImage *self);
-gsize gsk_vulkan_image_get_height (GskVulkanImage *self);
-VkImage gsk_vulkan_image_get_image (GskVulkanImage *self);
-VkImageView gsk_vulkan_image_get_image_view (GskVulkanImage *self);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_IMAGE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanlineargradientpipelineprivate.h"
-
-struct _GskVulkanLinearGradientPipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanLinearGradientInstance GskVulkanLinearGradientInstance;
-
-struct _GskVulkanLinearGradientInstance
-{
- float rect[4];
- float start[2];
- float end[2];
- gint32 repeating;
- gint32 stop_count;
- float offsets[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS];
- float colors[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS][4];
-};
-
-G_DEFINE_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanLinearGradientInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = 0,
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, start),
- },
- {
- .location = 2,
- .binding = 0,
- .format = VK_FORMAT_R32G32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, end),
- },
- {
- .location = 3,
- .binding = 0,
- .format = VK_FORMAT_R32_SINT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, repeating),
- },
- {
- .location = 4,
- .binding = 0,
- .format = VK_FORMAT_R32_SINT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, stop_count),
- },
- {
- .location = 5,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets),
- },
- {
- .location = 6,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets) + sizeof (float) * 4,
- },
- {
- .location = 7,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[0]),
- },
- {
- .location = 8,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[1]),
- },
- {
- .location = 9,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[2]),
- },
- {
- .location = 10,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[3]),
- },
- {
- .location = 11,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[4]),
- },
- {
- .location = 12,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[5]),
- },
- {
- .location = 13,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[6]),
- },
- {
- .location = 14,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[7]),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_linear_gradient_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanLinearGradientPipeline *self = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_linear_gradient_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_linear_gradient_pipeline_class_init (GskVulkanLinearGradientPipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_linear_gradient_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_linear_gradient_pipeline_init (GskVulkanLinearGradientPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_linear_gradient_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GskVulkanLinearGradientPipeline *pipeline)
-{
- return sizeof (GskVulkanLinearGradientInstance);
-}
-
-void
-gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradientPipeline *pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const graphene_point_t *start,
- const graphene_point_t *end,
- gboolean repeating,
- gsize n_stops,
- const GskColorStop *stops)
-{
- GskVulkanLinearGradientInstance *instance = (GskVulkanLinearGradientInstance *) data;
- gsize i;
-
- if (n_stops > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
- {
- g_warning ("Only %u color stops supported.", GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
- n_stops = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS;
- }
- instance->rect[0] = rect->origin.x;
- instance->rect[1] = rect->origin.y;
- instance->rect[2] = rect->size.width;
- instance->rect[3] = rect->size.height;
- instance->start[0] = start->x;
- instance->start[1] = start->y;
- instance->end[0] = end->x;
- instance->end[1] = end->y;
- instance->repeating = repeating;
- instance->stop_count = n_stops;
- for (i = 0; i < n_stops; i++)
- {
- instance->offsets[i] = stops[i].offset;
- instance->colors[i][0] = stops[i].color.red;
- instance->colors[i][1] = stops[i].color.green;
- instance->colors[i][2] = stops[i].color.blue;
- instance->colors[i][3] = stops[i].color.alpha;
- }
-}
-
-gsize
-gsk_vulkan_linear_gradient_pipeline_draw (GskVulkanLinearGradientPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskrendernode.h"
-
-G_BEGIN_DECLS
-
-#define GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS 8
-
-typedef struct _GskVulkanLinearGradientPipelineLayout GskVulkanLinearGradientPipelineLayout;
-
-#define GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE (gsk_vulkan_linear_gradient_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK, VULKAN_LINEAR_GRADIENT_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_linear_gradient_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_linear_gradient_pipeline_count_vertex_data
- (GskVulkanLinearGradientPipeline*pipeline);
-void gsk_vulkan_linear_gradient_pipeline_collect_vertex_data
- (GskVulkanLinearGradientPipeline*pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const graphene_point_t *start,
- const graphene_point_t *end,
- gboolean repeating,
- gsize n_stops,
- const GskColorStop *stops);
-gsize gsk_vulkan_linear_gradient_pipeline_draw (GskVulkanLinearGradientPipeline*pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanmemoryprivate.h"
-
-struct _GskVulkanMemory
-{
- GdkVulkanContext *vulkan;
-
- gsize size;
-
- VkDeviceMemory vk_memory;
-};
-
-GskVulkanMemory *
-gsk_vulkan_memory_new (GdkVulkanContext *context,
- uint32_t allowed_types,
- VkMemoryPropertyFlags flags,
- gsize size)
-{
- VkPhysicalDeviceMemoryProperties properties;
- GskVulkanMemory *self;
- uint32_t i;
-
- self = g_slice_new0 (GskVulkanMemory);
-
- self->vulkan = g_object_ref (context);
- self->size = size;
-
- vkGetPhysicalDeviceMemoryProperties (gdk_vulkan_context_get_physical_device (context),
- &properties);
-
- for (i = 0; i < properties.memoryTypeCount; i++)
- {
- if (!(allowed_types & (1 << i)))
- continue;
-
- if ((properties.memoryTypes[i].propertyFlags & flags) == flags)
- break;
- }
-
- g_assert (i < properties.memoryTypeCount);
-
- GSK_VK_CHECK (vkAllocateMemory, gdk_vulkan_context_get_device (context),
- &(VkMemoryAllocateInfo) {
- .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
- .allocationSize = size,
- .memoryTypeIndex = i
- },
- NULL,
- &self->vk_memory);
-
- return self;
-}
-
-void
-gsk_vulkan_memory_free (GskVulkanMemory *self)
-{
- vkFreeMemory (gdk_vulkan_context_get_device (self->vulkan),
- self->vk_memory,
- NULL);
-
- g_object_unref (self->vulkan);
-
- g_slice_free (GskVulkanMemory, self);
-}
-
-VkDeviceMemory
-gsk_vulkan_memory_get_device_memory (GskVulkanMemory *self)
-{
- return self->vk_memory;
-}
-
-guchar *
-gsk_vulkan_memory_map (GskVulkanMemory *self)
-{
- void *data;
-
- GSK_VK_CHECK (vkMapMemory, gdk_vulkan_context_get_device (self->vulkan),
- self->vk_memory,
- 0,
- self->size,
- 0,
- &data);
-
- return data;
-}
-
-void
-gsk_vulkan_memory_unmap (GskVulkanMemory *self)
-{
- vkUnmapMemory (gdk_vulkan_context_get_device (self->vulkan),
- self->vk_memory);
-}
-
+++ /dev/null
-#ifndef __GSK_VULKAN_MEMORY_PRIVATE_H__
-#define __GSK_VULKAN_MEMORY_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanMemory GskVulkanMemory;
-
-GskVulkanMemory * gsk_vulkan_memory_new (GdkVulkanContext *context,
- uint32_t allowed_types,
- VkMemoryPropertyFlags properties,
- gsize size);
-void gsk_vulkan_memory_free (GskVulkanMemory *memory);
-
-VkDeviceMemory gsk_vulkan_memory_get_device_memory (GskVulkanMemory *self);
-
-guchar * gsk_vulkan_memory_map (GskVulkanMemory *self);
-void gsk_vulkan_memory_unmap (GskVulkanMemory *self);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_MEMORY_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanpipelineprivate.h"
-
-#include "gskvulkanpushconstantsprivate.h"
-#include "gskvulkanshaderprivate.h"
-
-#include <graphene.h>
-
-typedef struct _GskVulkanPipelinePrivate GskVulkanPipelinePrivate;
-
-struct _GskVulkanPipelinePrivate
-{
- GObject parent_instance;
-
- GdkVulkanContext *context;
-
- VkPipeline pipeline;
- VkPipelineLayout layout;
-
- GskVulkanShader *vertex_shader;
- GskVulkanShader *fragment_shader;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (GskVulkanPipeline, gsk_vulkan_pipeline, G_TYPE_OBJECT)
-
-static void
-gsk_vulkan_pipeline_finalize (GObject *gobject)
-{
- GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (GSK_VULKAN_PIPELINE (gobject));
- VkDevice device;
-
- device = gdk_vulkan_context_get_device (priv->context);
-
- vkDestroyPipeline (device,
- priv->pipeline,
- NULL);
-
- g_clear_pointer (&priv->fragment_shader, gsk_vulkan_shader_free);
- g_clear_pointer (&priv->vertex_shader, gsk_vulkan_shader_free);
-
- G_OBJECT_CLASS (gsk_vulkan_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_pipeline_class_init (GskVulkanPipelineClass *klass)
-{
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_pipeline_finalize;
-}
-
-static void
-gsk_vulkan_pipeline_init (GskVulkanPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_pipeline_new (GType pipeline_type,
- GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new_full (pipeline_type, context, layout, shader_name, render_pass,
- VK_BLEND_FACTOR_ONE,
- VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
-}
-
-GskVulkanPipeline *
-gsk_vulkan_pipeline_new_full (GType pipeline_type,
- GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass,
- VkBlendFactor srcBlendFactor,
- VkBlendFactor dstBlendFactor)
-{
- GskVulkanPipelinePrivate *priv;
- GskVulkanPipeline *self;
- VkDevice device;
-
- g_return_val_if_fail (g_type_is_a (pipeline_type, GSK_TYPE_VULKAN_PIPELINE), NULL);
- g_return_val_if_fail (layout != VK_NULL_HANDLE, NULL);
- g_return_val_if_fail (shader_name != NULL, NULL);
- g_return_val_if_fail (render_pass != VK_NULL_HANDLE, NULL);
-
- self = g_object_new (pipeline_type, NULL);
-
- priv = gsk_vulkan_pipeline_get_instance_private (self);
-
- device = gdk_vulkan_context_get_device (context);
-
- priv->context = context;
- priv->layout = layout;
-
- priv->vertex_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_VERTEX, shader_name, NULL);
- priv->fragment_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_FRAGMENT, shader_name, NULL);
-
- GSK_VK_CHECK (vkCreateGraphicsPipelines, device,
- VK_NULL_HANDLE,
- 1,
- &(VkGraphicsPipelineCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
- .stageCount = 2,
- .pStages = (VkPipelineShaderStageCreateInfo[2]) {
- GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->vertex_shader),
- GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->fragment_shader)
- },
- .pVertexInputState = GSK_VULKAN_PIPELINE_GET_CLASS (self)->get_input_state_create_info (self),
- .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
- .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
- .primitiveRestartEnable = VK_FALSE,
- },
- .pTessellationState = NULL,
- .pViewportState = &(VkPipelineViewportStateCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
- .viewportCount = 1,
- .scissorCount = 1
- },
- .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
- .depthClampEnable = VK_FALSE,
- .rasterizerDiscardEnable = VK_FALSE,
- .polygonMode = VK_POLYGON_MODE_FILL,
- .cullMode = VK_CULL_MODE_BACK_BIT,
- .frontFace = VK_FRONT_FACE_CLOCKWISE,
- .lineWidth = 1.0f,
- },
- .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
- .rasterizationSamples = 1,
- },
- .pDepthStencilState = &(VkPipelineDepthStencilStateCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
- },
- .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
- .attachmentCount = 1,
- .pAttachments = (VkPipelineColorBlendAttachmentState []) {
- {
- .blendEnable = VK_TRUE,
- .colorBlendOp = VK_BLEND_OP_ADD,
- .srcColorBlendFactor = srcBlendFactor,
- .dstColorBlendFactor = dstBlendFactor,
- .alphaBlendOp = VK_BLEND_OP_ADD,
- .srcAlphaBlendFactor = srcBlendFactor,
- .dstAlphaBlendFactor = dstBlendFactor,
- .colorWriteMask = VK_COLOR_COMPONENT_A_BIT
- | VK_COLOR_COMPONENT_R_BIT
- | VK_COLOR_COMPONENT_G_BIT
- | VK_COLOR_COMPONENT_B_BIT
- },
- }
- },
- .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
- .dynamicStateCount = 2,
- .pDynamicStates = (VkDynamicState[2]) {
- VK_DYNAMIC_STATE_VIEWPORT,
- VK_DYNAMIC_STATE_SCISSOR
- },
- },
- .layout = priv->layout,
- .renderPass = render_pass,
- .subpass = 0,
- .basePipelineHandle = VK_NULL_HANDLE,
- .basePipelineIndex = -1,
- },
- NULL,
- &priv->pipeline);
-
- return self;
-}
-
-VkPipeline
-gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self)
-{
- GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (self);
-
- return priv->pipeline;
-}
-
-VkPipelineLayout
-gsk_vulkan_pipeline_get_pipeline_layout (GskVulkanPipeline *self)
-{
- GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (self);
-
- return priv->layout;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_PIPELINE_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-#include "gskdebugprivate.h"
-
-G_BEGIN_DECLS
-
-#define GSK_TYPE_VULKAN_PIPELINE (gsk_vulkan_pipeline_get_type ())
-
-G_DECLARE_DERIVABLE_TYPE (GskVulkanPipeline, gsk_vulkan_pipeline, GSK, VULKAN_PIPELINE, GObject)
-
-struct _GskVulkanPipelineClass
-{
- GObjectClass parent_class;
-
- const VkPipelineVertexInputStateCreateInfo *
- (* get_input_state_create_info) (GskVulkanPipeline *self);
-};
-
-static inline VkResult
-gsk_vulkan_handle_result (VkResult res,
- const char *called_function)
-{
- if (res != VK_SUCCESS)
- {
- GSK_NOTE (VULKAN,g_printerr ("%s(): %s (%d)\n", called_function, gdk_vulkan_strerror (res), res));
- }
- return res;
-}
-
-#define GSK_VK_CHECK(func, ...) gsk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func))
-
-GskVulkanPipeline * gsk_vulkan_pipeline_new (GType pipeline_type,
- GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-GskVulkanPipeline * gsk_vulkan_pipeline_new_full (GType pipeline_type,
- GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass,
- VkBlendFactor srcBlendFactor,
- VkBlendFactor dstBlendFactor);
-
-VkPipeline gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self);
-VkPipelineLayout gsk_vulkan_pipeline_get_pipeline_layout (GskVulkanPipeline *self);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanpushconstantsprivate.h"
-
-#include "gskroundedrectprivate.h"
-
-typedef struct _GskVulkanPushConstantsWire GskVulkanPushConstantsWire;
-
-struct _GskVulkanPushConstantsWire
-{
- struct {
- float mvp[16];
- float clip[12];
- } common;
-};
-
-void
-gsk_vulkan_push_constants_init (GskVulkanPushConstants *constants,
- const graphene_matrix_t *mvp,
- const graphene_rect_t *viewport)
-{
- graphene_matrix_init_from_matrix (&constants->mvp, mvp);
- gsk_vulkan_clip_init_empty (&constants->clip, viewport);
-}
-
-void
-gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants *self,
- const GskVulkanPushConstants *src)
-{
- *self = *src;
-}
-
-gboolean
-gsk_vulkan_push_constants_transform (GskVulkanPushConstants *self,
- const GskVulkanPushConstants *src,
- const graphene_matrix_t *transform,
- const graphene_rect_t *viewport)
-
-{
- if (!gsk_vulkan_clip_transform (&self->clip, &src->clip, transform, viewport))
- return FALSE;
-
- graphene_matrix_multiply (transform, &src->mvp, &self->mvp);
- return TRUE;
-}
-
-gboolean
-gsk_vulkan_push_constants_intersect_rect (GskVulkanPushConstants *self,
- const GskVulkanPushConstants *src,
- const graphene_rect_t *rect)
-{
- if (!gsk_vulkan_clip_intersect_rect (&self->clip, &src->clip, rect))
- return FALSE;
-
- graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
- return TRUE;
-}
-
-gboolean
-gsk_vulkan_push_constants_intersect_rounded (GskVulkanPushConstants *self,
- const GskVulkanPushConstants *src,
- const GskRoundedRect *rect)
-{
- if (!gsk_vulkan_clip_intersect_rounded_rect (&self->clip, &src->clip, rect))
- return FALSE;
-
- graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
- return TRUE;
-}
-
-static void
-gsk_vulkan_push_constants_wire_init (GskVulkanPushConstantsWire *wire,
- const GskVulkanPushConstants *self)
-{
- graphene_matrix_to_float (&self->mvp, wire->common.mvp);
- gsk_rounded_rect_to_float (&self->clip.rect, wire->common.clip);
-}
-
-void
-gsk_vulkan_push_constants_push (const GskVulkanPushConstants *self,
- VkCommandBuffer command_buffer,
- VkPipelineLayout pipeline_layout)
-{
- GskVulkanPushConstantsWire wire;
-
- gsk_vulkan_push_constants_wire_init (&wire, self);
-
- vkCmdPushConstants (command_buffer,
- pipeline_layout,
- VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
- G_STRUCT_OFFSET (GskVulkanPushConstantsWire, common),
- sizeof (wire.common),
- &wire.common);
-}
-
-uint32_t
-gsk_vulkan_push_constants_get_range_count (void)
-{
- return 1;
-}
-
-const VkPushConstantRange *
-gsk_vulkan_push_constants_get_ranges (void)
-{
- static const VkPushConstantRange ranges[1] = {
- {
- .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
- .offset = G_STRUCT_OFFSET (GskVulkanPushConstantsWire, common),
- .size = sizeof (((GskVulkanPushConstantsWire *) 0)->common)
- }
- };
-
- return ranges;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__
-#define __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__
-
-#include <gdk/gdk.h>
-#include <graphene.h>
-#include <gsk/gskvulkanclipprivate.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanPushConstants GskVulkanPushConstants;
-
-struct _GskVulkanPushConstants
-{
- graphene_matrix_t mvp;
- GskVulkanClip clip;
-};
-
-const VkPushConstantRange *
- gsk_vulkan_push_constants_get_ranges (void) G_GNUC_PURE;
-uint32_t gsk_vulkan_push_constants_get_range_count (void) G_GNUC_PURE;
-
-void gsk_vulkan_push_constants_init (GskVulkanPushConstants *constants,
- const graphene_matrix_t *mvp,
- const graphene_rect_t *viewport);
-void gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants *self,
- const GskVulkanPushConstants *src);
-
-gboolean gsk_vulkan_push_constants_transform (GskVulkanPushConstants *self,
- const GskVulkanPushConstants *src,
- const graphene_matrix_t *transform,
- const graphene_rect_t *viewport);
-gboolean gsk_vulkan_push_constants_intersect_rect (GskVulkanPushConstants *self,
- const GskVulkanPushConstants *src,
- const graphene_rect_t *rect);
-gboolean gsk_vulkan_push_constants_intersect_rounded (GskVulkanPushConstants *self,
- const GskVulkanPushConstants *src,
- const GskRoundedRect *rect);
-
-void gsk_vulkan_push_constants_push (const GskVulkanPushConstants *self,
- VkCommandBuffer command_buffer,
- VkPipelineLayout pipeline_layout);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskprivate.h"
-
-#include "gskvulkanrenderprivate.h"
-
-#include "gskrendererprivate.h"
-#include "gskvulkanbufferprivate.h"
-#include "gskvulkancommandpoolprivate.h"
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanrenderpassprivate.h"
-
-#include "gskvulkanblendmodepipelineprivate.h"
-#include "gskvulkanblurpipelineprivate.h"
-#include "gskvulkanborderpipelineprivate.h"
-#include "gskvulkanboxshadowpipelineprivate.h"
-#include "gskvulkancolorpipelineprivate.h"
-#include "gskvulkancolortextpipelineprivate.h"
-#include "gskvulkancrossfadepipelineprivate.h"
-#include "gskvulkaneffectpipelineprivate.h"
-#include "gskvulkanlineargradientpipelineprivate.h"
-#include "gskvulkantextpipelineprivate.h"
-#include "gskvulkantexturepipelineprivate.h"
-#include "gskvulkanpushconstantsprivate.h"
-
-#define DESCRIPTOR_POOL_MAXSETS 128
-#define DESCRIPTOR_POOL_MAXSETS_INCREASE 128
-
-struct _GskVulkanRender
-{
- GskRenderer *renderer;
- GdkVulkanContext *vulkan;
-
- int scale_factor;
- graphene_rect_t viewport;
- cairo_region_t *clip;
-
- GHashTable *framebuffers;
- GskVulkanCommandPool *command_pool;
- VkFence fence;
- VkRenderPass render_pass;
- VkDescriptorSetLayout descriptor_set_layout;
- VkPipelineLayout pipeline_layout[3]; /* indexed by number of textures */
- GskVulkanUploader *uploader;
-
- GHashTable *descriptor_set_indexes;
- VkDescriptorPool descriptor_pool;
- uint32_t descriptor_pool_maxsets;
- VkDescriptorSet *descriptor_sets;
- gsize n_descriptor_sets;
- GskVulkanPipeline *pipelines[GSK_VULKAN_N_PIPELINES];
-
- GskVulkanImage *target;
-
- VkSampler sampler;
- VkSampler repeating_sampler;
-
- GList *render_passes;
- GSList *cleanup_images;
-
- GQuark render_pass_counter;
- GQuark gpu_time_timer;
-};
-
-static void
-gsk_vulkan_render_setup (GskVulkanRender *self,
- GskVulkanImage *target,
- const graphene_rect_t *rect)
-{
- GdkWindow *window = gsk_renderer_get_window (self->renderer);
-
- self->target = g_object_ref (target);
-
- if (rect)
- {
- self->viewport = *rect;
- self->scale_factor = 1;
- self->clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
- 0, 0,
- gsk_vulkan_image_get_width (target),
- gsk_vulkan_image_get_height (target)
- });
- }
- else
- {
- self->scale_factor = gdk_window_get_scale_factor (gsk_renderer_get_window (self->renderer));
- self->viewport = GRAPHENE_RECT_INIT (0, 0,
- gdk_window_get_width (window) * self->scale_factor,
- gdk_window_get_height (window) * self->scale_factor);
- self->clip = gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (self->renderer));
- }
-}
-
-static guint desc_set_index_hash (gconstpointer v);
-static gboolean desc_set_index_equal (gconstpointer v1, gconstpointer v2);
-
-GskVulkanRender *
-gsk_vulkan_render_new (GskRenderer *renderer,
- GdkVulkanContext *context)
-{
- GskVulkanRender *self;
- VkDevice device;
-
- self = g_slice_new0 (GskVulkanRender);
-
- self->vulkan = context;
- self->renderer = renderer;
- self->framebuffers = g_hash_table_new (g_direct_hash, g_direct_equal);
- self->descriptor_set_indexes = g_hash_table_new_full (desc_set_index_hash, desc_set_index_equal, NULL, g_free);
-
- device = gdk_vulkan_context_get_device (self->vulkan);
-
- self->command_pool = gsk_vulkan_command_pool_new (self->vulkan);
- GSK_VK_CHECK (vkCreateFence, device,
- &(VkFenceCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
- .flags = VK_FENCE_CREATE_SIGNALED_BIT
- },
- NULL,
- &self->fence);
-
- self->descriptor_pool_maxsets = DESCRIPTOR_POOL_MAXSETS;
- GSK_VK_CHECK (vkCreateDescriptorPool, device,
- &(VkDescriptorPoolCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
- .maxSets = self->descriptor_pool_maxsets,
- .poolSizeCount = 1,
- .pPoolSizes = (VkDescriptorPoolSize[1]) {
- {
- .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
- .descriptorCount = self->descriptor_pool_maxsets
- }
- }
- },
- NULL,
- &self->descriptor_pool);
-
- GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
- &(VkRenderPassCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
- .attachmentCount = 1,
- .pAttachments = (VkAttachmentDescription[]) {
- {
- .format = gdk_vulkan_context_get_image_format (self->vulkan),
- .samples = VK_SAMPLE_COUNT_1_BIT,
- .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
- .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
- .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
- .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
- }
- },
- .subpassCount = 1,
- .pSubpasses = (VkSubpassDescription []) {
- {
- .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
- .inputAttachmentCount = 0,
- .colorAttachmentCount = 1,
- .pColorAttachments = (VkAttachmentReference []) {
- {
- .attachment = 0,
- .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
- }
- },
- .pResolveAttachments = (VkAttachmentReference []) {
- {
- .attachment = VK_ATTACHMENT_UNUSED,
- .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
- }
- },
- .pDepthStencilAttachment = NULL,
- }
- },
- .dependencyCount = 0
- },
- NULL,
- &self->render_pass);
-
- GSK_VK_CHECK (vkCreateDescriptorSetLayout, device,
- &(VkDescriptorSetLayoutCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
- .bindingCount = 1,
- .pBindings = (VkDescriptorSetLayoutBinding[1]) {
- {
- .binding = 0,
- .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
- .descriptorCount = 1,
- .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
- }
- }
- },
- NULL,
- &self->descriptor_set_layout);
-
- for (guint i = 0; i < 3; i++)
- {
- VkDescriptorSetLayout layouts[3] = {
- self->descriptor_set_layout,
- self->descriptor_set_layout,
- self->descriptor_set_layout
- };
-
- GSK_VK_CHECK (vkCreatePipelineLayout, device,
- &(VkPipelineLayoutCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
- .setLayoutCount = i,
- .pSetLayouts = layouts,
- .pushConstantRangeCount = gsk_vulkan_push_constants_get_range_count (),
- .pPushConstantRanges = gsk_vulkan_push_constants_get_ranges ()
- },
- NULL,
- &self->pipeline_layout[i]);
- }
-
- GSK_VK_CHECK (vkCreateSampler, device,
- &(VkSamplerCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
- .magFilter = VK_FILTER_LINEAR,
- .minFilter = VK_FILTER_LINEAR,
- .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
- .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
- .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
- .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
- .unnormalizedCoordinates = VK_FALSE,
- .maxAnisotropy = 1.0,
- },
- NULL,
- &self->sampler);
-
- GSK_VK_CHECK (vkCreateSampler, device,
- &(VkSamplerCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
- .magFilter = VK_FILTER_LINEAR,
- .minFilter = VK_FILTER_LINEAR,
- .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
- .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
- .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
- .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
- .unnormalizedCoordinates = VK_FALSE,
- .maxAnisotropy = 1.0,
- },
- NULL,
- &self->repeating_sampler);
-
- self->uploader = gsk_vulkan_uploader_new (self->vulkan, self->command_pool);
-
-#ifdef G_ENABLE_DEBUG
- self->render_pass_counter = g_quark_from_static_string ("render-passes");
- self->gpu_time_timer = g_quark_from_static_string ("gpu-time");
-#endif
-
- return self;
-}
-
-typedef struct {
- VkFramebuffer framebuffer;
-} HashFramebufferEntry;
-
-static void
-gsk_vulkan_render_remove_framebuffer_from_image (gpointer data,
- GObject *image)
-{
- GskVulkanRender *self = data;
- HashFramebufferEntry *fb;
-
- fb = g_hash_table_lookup (self->framebuffers, image);
- g_hash_table_remove (self->framebuffers, image);
-
- vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
- fb->framebuffer,
- NULL);
-
- g_slice_free (HashFramebufferEntry, fb);
-}
-
-VkFramebuffer
-gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
- GskVulkanImage *image)
-{
- HashFramebufferEntry *fb;
-
- fb = g_hash_table_lookup (self->framebuffers, image);
- if (fb)
- return fb->framebuffer;
-
- fb = g_slice_new0 (HashFramebufferEntry);
- GSK_VK_CHECK (vkCreateFramebuffer, gdk_vulkan_context_get_device (self->vulkan),
- &(VkFramebufferCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
- .renderPass = self->render_pass,
- .attachmentCount = 1,
- .pAttachments = (VkImageView[1]) {
- gsk_vulkan_image_get_image_view (image)
- },
- .width = gsk_vulkan_image_get_width (image),
- .height = gsk_vulkan_image_get_height (image),
- .layers = 1
- },
- NULL,
- &fb->framebuffer);
- g_hash_table_insert (self->framebuffers, image, fb);
- g_object_weak_ref (G_OBJECT (image), gsk_vulkan_render_remove_framebuffer_from_image, self);
-
- return fb->framebuffer;
-}
-
-void
-gsk_vulkan_render_add_cleanup_image (GskVulkanRender *self,
- GskVulkanImage *image)
-{
- self->cleanup_images = g_slist_prepend (self->cleanup_images, image);
-}
-
-void
-gsk_vulkan_render_add_render_pass (GskVulkanRender *self,
- GskVulkanRenderPass *pass)
-{
- self->render_passes = g_list_prepend (self->render_passes, pass);
-
-#ifdef G_ENABLE_DEBUG
- gsk_profiler_counter_inc (gsk_renderer_get_profiler (self->renderer), self->render_pass_counter);
-#endif
-}
-
-void
-gsk_vulkan_render_add_node (GskVulkanRender *self,
- GskRenderNode *node)
-{
- GskVulkanRenderPass *pass;
- graphene_matrix_t mv;
-
- graphene_matrix_init_scale (&mv, self->scale_factor, self->scale_factor, 1.0);
-
- pass = gsk_vulkan_render_pass_new (self->vulkan,
- self->target,
- self->scale_factor,
- &mv,
- &self->viewport,
- self->clip,
- VK_NULL_HANDLE);
-
- gsk_vulkan_render_add_render_pass (self, pass);
-
- gsk_vulkan_render_pass_add (pass, self, node);
-}
-
-void
-gsk_vulkan_render_upload (GskVulkanRender *self)
-{
- GList *l;
-
- /* gsk_vulkan_render_pass_upload may call gsk_vulkan_render_add_node_for_texture,
- * prepending new render passes to the list. Therefore, we walk the list from
- * the end.
- */
- for (l = g_list_last (self->render_passes); l; l = l->prev)
- {
- GskVulkanRenderPass *pass = l->data;
- gsk_vulkan_render_pass_upload (pass, self, self->uploader);
- }
-
- gsk_vulkan_uploader_upload (self->uploader);
-}
-
-GskVulkanPipeline *
-gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
- GskVulkanPipelineType type)
-{
- static const struct {
- const char *name;
- guint num_textures;
- GskVulkanPipeline * (* create_func) (GdkVulkanContext *context, VkPipelineLayout layout, const char *name, VkRenderPass render_pass);
- } pipeline_info[GSK_VULKAN_N_PIPELINES] = {
- { "texture", 1, gsk_vulkan_texture_pipeline_new },
- { "texture-clip", 1, gsk_vulkan_texture_pipeline_new },
- { "texture-clip-rounded", 1, gsk_vulkan_texture_pipeline_new },
- { "color", 0, gsk_vulkan_color_pipeline_new },
- { "color-clip", 0, gsk_vulkan_color_pipeline_new },
- { "color-clip-rounded", 0, gsk_vulkan_color_pipeline_new },
- { "linear", 0, gsk_vulkan_linear_gradient_pipeline_new },
- { "linear-clip", 0, gsk_vulkan_linear_gradient_pipeline_new },
- { "linear-clip-rounded", 0, gsk_vulkan_linear_gradient_pipeline_new },
- { "color-matrix", 1, gsk_vulkan_effect_pipeline_new },
- { "color-matrix-clip", 1, gsk_vulkan_effect_pipeline_new },
- { "color-matrix-clip-rounded", 1, gsk_vulkan_effect_pipeline_new },
- { "border", 0, gsk_vulkan_border_pipeline_new },
- { "border-clip", 0, gsk_vulkan_border_pipeline_new },
- { "border-clip-rounded", 0, gsk_vulkan_border_pipeline_new },
- { "inset-shadow", 0, gsk_vulkan_box_shadow_pipeline_new },
- { "inset-shadow-clip", 0, gsk_vulkan_box_shadow_pipeline_new },
- { "inset-shadow-clip-rounded", 0, gsk_vulkan_box_shadow_pipeline_new },
- { "outset-shadow", 0, gsk_vulkan_box_shadow_pipeline_new },
- { "outset-shadow-clip", 0, gsk_vulkan_box_shadow_pipeline_new },
- { "outset-shadow-clip-rounded", 0, gsk_vulkan_box_shadow_pipeline_new },
- { "blur", 1, gsk_vulkan_blur_pipeline_new },
- { "blur-clip", 1, gsk_vulkan_blur_pipeline_new },
- { "blur-clip-rounded", 1, gsk_vulkan_blur_pipeline_new },
- { "mask", 1, gsk_vulkan_text_pipeline_new },
- { "mask-clip", 1, gsk_vulkan_text_pipeline_new },
- { "mask-clip-rounded", 1, gsk_vulkan_text_pipeline_new },
- { "texture", 1, gsk_vulkan_color_text_pipeline_new },
- { "texture-clip", 1, gsk_vulkan_color_text_pipeline_new },
- { "texture-clip-rounded", 1, gsk_vulkan_color_text_pipeline_new },
- { "crossfade", 2, gsk_vulkan_cross_fade_pipeline_new },
- { "crossfade-clip", 2, gsk_vulkan_cross_fade_pipeline_new },
- { "crossfade-clip-rounded", 2, gsk_vulkan_cross_fade_pipeline_new },
- { "blendmode", 2, gsk_vulkan_blend_mode_pipeline_new },
- { "blendmode-clip", 2, gsk_vulkan_blend_mode_pipeline_new },
- { "blendmode-clip-rounded", 2, gsk_vulkan_blend_mode_pipeline_new },
- };
-
- g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);
-
- if (self->pipelines[type] == NULL)
- self->pipelines[type] = pipeline_info[type].create_func (self->vulkan,
- self->pipeline_layout[pipeline_info[type].num_textures],
- pipeline_info[type].name,
- self->render_pass);
-
- return self->pipelines[type];
-}
-
-VkDescriptorSet
-gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
- gsize id)
-{
- g_assert (id < self->n_descriptor_sets);
-
- return self->descriptor_sets[id];
-}
-
-typedef struct {
- gsize index;
- GskVulkanImage *image;
- gboolean repeat;
-} HashDescriptorSetIndexEntry;
-
-static guint
-desc_set_index_hash (gconstpointer v)
-{
- const HashDescriptorSetIndexEntry *e = v;
-
- return GPOINTER_TO_UINT (e->image) + e->repeat;
-}
-
-static gboolean
-desc_set_index_equal (gconstpointer v1, gconstpointer v2)
-{
- const HashDescriptorSetIndexEntry *e1 = v1;
- const HashDescriptorSetIndexEntry *e2 = v2;
-
- return e1->image == e2->image && e1->repeat == e2->repeat;
-}
-
-gsize
-gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
- GskVulkanImage *source,
- gboolean repeat)
-{
- HashDescriptorSetIndexEntry lookup;
- HashDescriptorSetIndexEntry *entry;
-
- g_assert (source != NULL);
-
- lookup.image = source;
- lookup.repeat = repeat;
-
- entry = g_hash_table_lookup (self->descriptor_set_indexes, &lookup);
- if (entry)
- return entry->index;
-
- entry = g_new (HashDescriptorSetIndexEntry, 1);
- entry->image = source;
- entry->repeat = repeat;
- entry->index = g_hash_table_size (self->descriptor_set_indexes);
- g_hash_table_add (self->descriptor_set_indexes, entry);
-
- return entry->index;
-}
-
-static void
-gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self)
-{
- GHashTableIter iter;
- gpointer key;
- VkDevice device;
- GList *l;
- guint i, needed_sets;
-
- device = gdk_vulkan_context_get_device (self->vulkan);
-
- for (l = self->render_passes; l; l = l->next)
- {
- GskVulkanRenderPass *pass = l->data;
- gsk_vulkan_render_pass_reserve_descriptor_sets (pass, self);
- }
-
- needed_sets = g_hash_table_size (self->descriptor_set_indexes);
- if (needed_sets > self->n_descriptor_sets)
- {
- if (needed_sets > self->descriptor_pool_maxsets)
- {
- guint added_sets = needed_sets - self->descriptor_pool_maxsets;
- added_sets = added_sets + DESCRIPTOR_POOL_MAXSETS_INCREASE - 1;
- added_sets -= added_sets % DESCRIPTOR_POOL_MAXSETS_INCREASE;
-
- vkDestroyDescriptorPool (device,
- self->descriptor_pool,
- NULL);
- self->descriptor_pool_maxsets += added_sets;
- GSK_VK_CHECK (vkCreateDescriptorPool, device,
- &(VkDescriptorPoolCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
- .maxSets = self->descriptor_pool_maxsets,
- .poolSizeCount = 1,
- .pPoolSizes = (VkDescriptorPoolSize[1]) {
- {
- .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
- .descriptorCount = self->descriptor_pool_maxsets
- }
- }
- },
- NULL,
- &self->descriptor_pool);
- }
- else
- {
- GSK_VK_CHECK (vkResetDescriptorPool, device,
- self->descriptor_pool,
- 0);
- }
-
- self->n_descriptor_sets = needed_sets;
- self->descriptor_sets = g_renew (VkDescriptorSet, self->descriptor_sets, needed_sets);
- }
-
- VkDescriptorSetLayout *layouts = g_newa (VkDescriptorSetLayout, needed_sets);
- for (i = 0; i < needed_sets; i++)
- layouts[i] = self->descriptor_set_layout;
-
- GSK_VK_CHECK (vkAllocateDescriptorSets, device,
- &(VkDescriptorSetAllocateInfo) {
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
- .descriptorPool = self->descriptor_pool,
- .descriptorSetCount = needed_sets,
- .pSetLayouts = layouts
- },
- self->descriptor_sets);
-
- g_hash_table_iter_init (&iter, self->descriptor_set_indexes);
- while (g_hash_table_iter_next (&iter, &key, NULL))
- {
- HashDescriptorSetIndexEntry *entry = key;
- GskVulkanImage *image = entry->image;
- gsize id = entry->index;
- gboolean repeat = entry->repeat;
-
- vkUpdateDescriptorSets (device,
- 1,
- (VkWriteDescriptorSet[1]) {
- {
- .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
- .dstSet = self->descriptor_sets[id],
- .dstBinding = 0,
- .dstArrayElement = 0,
- .descriptorCount = 1,
- .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
- .pImageInfo = &(VkDescriptorImageInfo) {
- .sampler = repeat ? self->repeating_sampler : self->sampler,
- .imageView = gsk_vulkan_image_get_image_view (image),
- .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
- }
- }
- },
- 0, NULL);
- }
-}
-
-void
-gsk_vulkan_render_draw (GskVulkanRender *self)
-{
- GList *l;
-
-#ifdef G_ENABLE_DEBUG
- if (GSK_RENDER_MODE_CHECK (SYNC))
- gsk_profiler_timer_begin (gsk_renderer_get_profiler (self->renderer), self->gpu_time_timer);
-#endif
-
- gsk_vulkan_render_prepare_descriptor_sets (self);
-
- for (l = self->render_passes; l; l = l->next)
- {
- GskVulkanRenderPass *pass = l->data;
- VkCommandBuffer command_buffer;
- gsize wait_semaphore_count;
- gsize signal_semaphore_count;
- VkSemaphore *wait_semaphores;
- VkSemaphore *signal_semaphores;
-
- wait_semaphore_count = gsk_vulkan_render_pass_get_wait_semaphores (pass, &wait_semaphores);
- signal_semaphore_count = gsk_vulkan_render_pass_get_signal_semaphores (pass, &signal_semaphores);
-
- command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
-
- gsk_vulkan_render_pass_draw (pass, self, 3, self->pipeline_layout, command_buffer);
-
- gsk_vulkan_command_pool_submit_buffer (self->command_pool,
- command_buffer,
- wait_semaphore_count,
- wait_semaphores,
- signal_semaphore_count,
- signal_semaphores,
- l->next != NULL ? VK_NULL_HANDLE : self->fence);
- }
-
- if (GSK_RENDER_MODE_CHECK (SYNC))
- {
- GskProfiler *profiler;
- gint64 gpu_time;
-
- GSK_VK_CHECK (vkWaitForFences, gdk_vulkan_context_get_device (self->vulkan),
- 1,
- &self->fence,
- VK_TRUE,
- INT64_MAX);
-
- profiler = gsk_renderer_get_profiler (self->renderer);
- gpu_time = gsk_profiler_timer_end (profiler, self->gpu_time_timer);
- gsk_profiler_timer_set (profiler, self->gpu_time_timer, gpu_time);
- }
-}
-
-GdkTexture *
-gsk_vulkan_render_download_target (GskVulkanRender *self)
-{
- gsk_vulkan_uploader_reset (self->uploader);
-
- return gsk_vulkan_image_download (self->target, self->uploader);
-}
-
-static void
-gsk_vulkan_render_cleanup (GskVulkanRender *self)
-{
- VkDevice device = gdk_vulkan_context_get_device (self->vulkan);
-
- /* XXX: Wait for fence here or just in reset()? */
- GSK_VK_CHECK (vkWaitForFences, device,
- 1,
- &self->fence,
- VK_TRUE,
- INT64_MAX);
-
- GSK_VK_CHECK (vkResetFences, device,
- 1,
- &self->fence);
-
- gsk_vulkan_uploader_reset (self->uploader);
-
- gsk_vulkan_command_pool_reset (self->command_pool);
-
- g_hash_table_remove_all (self->descriptor_set_indexes);
- GSK_VK_CHECK (vkResetDescriptorPool, device,
- self->descriptor_pool,
- 0);
-
- g_list_free_full (self->render_passes, (GDestroyNotify) gsk_vulkan_render_pass_free);
- self->render_passes = NULL;
- g_slist_free_full (self->cleanup_images, g_object_unref);
- self->cleanup_images = NULL;
-
- g_clear_pointer (&self->clip, cairo_region_destroy);
- g_clear_object (&self->target);
-}
-
-void
-gsk_vulkan_render_free (GskVulkanRender *self)
-{
- GHashTableIter iter;
- gpointer key, value;
- VkDevice device;
- guint i;
-
- gsk_vulkan_render_cleanup (self);
-
- device = gdk_vulkan_context_get_device (self->vulkan);
-
- g_hash_table_iter_init (&iter, self->framebuffers);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- HashFramebufferEntry *fb = value;
-
- vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
- fb->framebuffer,
- NULL);
- g_slice_free (HashFramebufferEntry, fb);
- g_object_weak_unref (G_OBJECT (key), gsk_vulkan_render_remove_framebuffer_from_image, self);
- g_hash_table_iter_remove (&iter);
- }
- g_hash_table_unref (self->framebuffers);
-
- for (i = 0; i < GSK_VULKAN_N_PIPELINES; i++)
- g_clear_object (&self->pipelines[i]);
-
- g_clear_pointer (&self->uploader, gsk_vulkan_uploader_free);
-
- for (i = 0; i < 3; i++)
- vkDestroyPipelineLayout (device,
- self->pipeline_layout[i],
- NULL);
-
- vkDestroyRenderPass (device,
- self->render_pass,
- NULL);
-
- vkDestroyDescriptorPool (device,
- self->descriptor_pool,
- NULL);
- g_free (self->descriptor_sets);
- g_hash_table_unref (self->descriptor_set_indexes);
-
- vkDestroyDescriptorSetLayout (device,
- self->descriptor_set_layout,
- NULL);
-
- vkDestroyFence (device,
- self->fence,
- NULL);
-
- vkDestroySampler (device,
- self->sampler,
- NULL);
-
- vkDestroySampler (device,
- self->repeating_sampler,
- NULL);
-
- gsk_vulkan_command_pool_free (self->command_pool);
-
- g_slice_free (GskVulkanRender, self);
-}
-
-gboolean
-gsk_vulkan_render_is_busy (GskVulkanRender *self)
-{
- return vkGetFenceStatus (gdk_vulkan_context_get_device (self->vulkan), self->fence) != VK_SUCCESS;
-}
-
-void
-gsk_vulkan_render_reset (GskVulkanRender *self,
- GskVulkanImage *target,
- const graphene_rect_t *rect)
-{
- gsk_vulkan_render_cleanup (self);
-
- gsk_vulkan_render_setup (self, target, rect);
-}
-
-GskRenderer *
-gsk_vulkan_render_get_renderer (GskVulkanRender *self)
-{
- return self->renderer;
-}
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanrendererprivate.h"
-
-#include "gskdebugprivate.h"
-#include "gskprivate.h"
-#include "gskrendererprivate.h"
-#include "gskrendernodeprivate.h"
-#include "gskvulkanbufferprivate.h"
-#include "gskvulkanimageprivate.h"
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanrenderprivate.h"
-#include "gskvulkanglyphcacheprivate.h"
-
-#include "gdk/gdktextureprivate.h"
-
-#include <graphene.h>
-
-typedef struct _GskVulkanTextureData GskVulkanTextureData;
-
-struct _GskVulkanTextureData {
- GdkTexture *texture;
- GskVulkanImage *image;
- GskVulkanRenderer *renderer;
-};
-
-#ifdef G_ENABLE_DEBUG
-typedef struct {
- GQuark frames;
- GQuark render_passes;
- GQuark fallback_pixels;
- GQuark texture_pixels;
-} ProfileCounters;
-
-typedef struct {
- GQuark cpu_time;
- GQuark gpu_time;
-} ProfileTimers;
-#endif
-
-struct _GskVulkanRenderer
-{
- GskRenderer parent_instance;
-
- GdkVulkanContext *vulkan;
-
- guint n_targets;
- GskVulkanImage **targets;
-
- GskVulkanRender *render;
-
- GSList *textures;
-
- GskVulkanGlyphCache *glyph_cache;
-
-#ifdef G_ENABLE_DEBUG
- ProfileCounters profile_counters;
- ProfileTimers profile_timers;
-#endif
-};
-
-struct _GskVulkanRendererClass
-{
- GskRendererClass parent_class;
-};
-
-G_DEFINE_TYPE (GskVulkanRenderer, gsk_vulkan_renderer, GSK_TYPE_RENDERER)
-
-static void
-gsk_vulkan_renderer_free_targets (GskVulkanRenderer *self)
-{
- guint i;
-
- for (i = 0; i < self->n_targets; i++)
- {
- g_object_unref (self->targets[i]);
- }
-
- g_clear_pointer (&self->targets, g_free);
- self->n_targets = 0;
-}
-
-static void
-gsk_vulkan_renderer_update_images_cb (GdkVulkanContext *context,
- GskVulkanRenderer *self)
-{
- GdkWindow *window;
- gint scale_factor;
- gsize width, height;
- guint i;
-
- gsk_vulkan_renderer_free_targets (self);
-
- self->n_targets = gdk_vulkan_context_get_n_images (context);
- self->targets = g_new (GskVulkanImage *, self->n_targets);
-
- window = gsk_renderer_get_window (GSK_RENDERER (self));
- scale_factor = gdk_window_get_scale_factor (window);
- width = gdk_window_get_width (window) * scale_factor;
- height = gdk_window_get_height (window) * scale_factor;
-
- for (i = 0; i < self->n_targets; i++)
- {
- self->targets[i] = gsk_vulkan_image_new_for_swapchain (self->vulkan,
- gdk_vulkan_context_get_image (context, i),
- gdk_vulkan_context_get_image_format (self->vulkan),
- width, height);
- }
-}
-
-static gboolean
-gsk_vulkan_renderer_realize (GskRenderer *renderer,
- GdkWindow *window,
- GError **error)
-{
- GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
-
- self->vulkan = gdk_window_create_vulkan_context (window, error);
- if (self->vulkan == NULL)
- return FALSE;
-
- g_signal_connect (self->vulkan,
- "images-updated",
- G_CALLBACK (gsk_vulkan_renderer_update_images_cb),
- self);
- gsk_vulkan_renderer_update_images_cb (self->vulkan, self);
-
- self->render = gsk_vulkan_render_new (renderer, self->vulkan);
-
- self->glyph_cache = gsk_vulkan_glyph_cache_new (self->vulkan);
-
- return TRUE;
-}
-
-static void
-gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
-{
- GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
- GSList *l;
-
- g_clear_object (&self->glyph_cache);
-
- for (l = self->textures; l; l = l->next)
- {
- GskVulkanTextureData *data = l->data;
-
- data->renderer = NULL;
- gdk_texture_clear_render_data (data->texture);
- }
- g_clear_pointer (&self->textures, (GDestroyNotify) g_slist_free);
-
- g_clear_pointer (&self->render, gsk_vulkan_render_free);
-
- gsk_vulkan_renderer_free_targets (self);
- g_signal_handlers_disconnect_by_func(self->vulkan,
- gsk_vulkan_renderer_update_images_cb,
- self);
-
- g_clear_object (&self->vulkan);
-}
-
-static GdkTexture *
-gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
- GskRenderNode *root,
- const graphene_rect_t *viewport)
-{
- GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
- GskVulkanRender *render;
- GskVulkanImage *image;
- GdkTexture *texture;
-#ifdef G_ENABLE_DEBUG
- GskProfiler *profiler;
- gint64 cpu_time;
-#endif
-
-#ifdef G_ENABLE_DEBUG
- profiler = gsk_renderer_get_profiler (renderer);
- gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
- gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
- gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
- gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
-#endif
-
- render = gsk_vulkan_render_new (renderer, self->vulkan);
-
- image = gsk_vulkan_image_new_for_framebuffer (self->vulkan,
- ceil (viewport->size.width),
- ceil (viewport->size.height));
-
- gsk_vulkan_render_reset (render, image, viewport);
-
- gsk_vulkan_render_add_node (render, root);
-
- gsk_vulkan_render_upload (render);
-
- gsk_vulkan_render_draw (render);
-
- texture = gsk_vulkan_render_download_target (render);
-
- g_object_unref (image);
- gsk_vulkan_render_free (render);
-
-#ifdef G_ENABLE_DEBUG
- cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
- gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
-
- gsk_profiler_push_samples (profiler);
-#endif
-
- return texture;
-}
-
-static void
-gsk_vulkan_renderer_render (GskRenderer *renderer,
- GskRenderNode *root)
-{
- GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
- GskVulkanRender *render;
-#ifdef G_ENABLE_DEBUG
- GskProfiler *profiler;
- gint64 cpu_time;
-#endif
-
-#ifdef G_ENABLE_DEBUG
- profiler = gsk_renderer_get_profiler (renderer);
- gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
- gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
- gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
- gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
-#endif
-
- render = self->render;
-
- gsk_vulkan_render_reset (render, self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)], NULL);
-
- gsk_vulkan_render_add_node (render, root);
-
- gsk_vulkan_render_upload (render);
-
- gsk_vulkan_render_draw (render);
-
-#ifdef G_ENABLE_DEBUG
- gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
-
- cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
- gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
-
- gsk_profiler_push_samples (profiler);
-#endif
-}
-
-static GdkDrawingContext *
-gsk_vulkan_renderer_begin_draw_frame (GskRenderer *renderer,
- const cairo_region_t *region)
-{
- GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
- GdkDrawingContext *result;
-
- result = gdk_window_begin_draw_frame (gsk_renderer_get_window (renderer),
- GDK_DRAW_CONTEXT (self->vulkan),
- region);
-
- return result;
-}
-
-static void
-gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass)
-{
- GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
-
- renderer_class->realize = gsk_vulkan_renderer_realize;
- renderer_class->unrealize = gsk_vulkan_renderer_unrealize;
- renderer_class->render = gsk_vulkan_renderer_render;
- renderer_class->render_texture = gsk_vulkan_renderer_render_texture;
- renderer_class->begin_draw_frame = gsk_vulkan_renderer_begin_draw_frame;
-}
-
-static void
-gsk_vulkan_renderer_init (GskVulkanRenderer *self)
-{
-#ifdef G_ENABLE_DEBUG
- GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
-#endif
-
- gsk_ensure_resources ();
-
-#ifdef G_ENABLE_DEBUG
- self->profile_counters.frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE);
- self->profile_counters.render_passes = gsk_profiler_add_counter (profiler, "render-passes", "Render passes", FALSE);
- self->profile_counters.fallback_pixels = gsk_profiler_add_counter (profiler, "fallback-pixels", "Fallback pixels", TRUE);
- self->profile_counters.texture_pixels = gsk_profiler_add_counter (profiler, "texture-pixels", "Texture pixels", TRUE);
-
- self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
- if (GSK_RENDER_MODE_CHECK (SYNC))
- self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
-#endif
-}
-
-static void
-gsk_vulkan_renderer_clear_texture (gpointer p)
-{
- GskVulkanTextureData *data = p;
-
- if (data->renderer != NULL)
- data->renderer->textures = g_slist_remove (data->renderer->textures, data);
-
- g_object_unref (data->image);
-
- g_slice_free (GskVulkanTextureData, data);
-}
-
-GskVulkanImage *
-gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
- GdkTexture *texture,
- GskVulkanUploader *uploader)
-{
- GskVulkanTextureData *data;
- cairo_surface_t *surface;
- GskVulkanImage *image;
-
- data = gdk_texture_get_render_data (texture, self);
- if (data)
- return g_object_ref (data->image);
-
- surface = gdk_texture_download_surface (texture);
- image = gsk_vulkan_image_new_from_data (uploader,
- cairo_image_surface_get_data (surface),
- cairo_image_surface_get_width (surface),
- cairo_image_surface_get_height (surface),
- cairo_image_surface_get_stride (surface));
- cairo_surface_destroy (surface);
-
- data = g_slice_new0 (GskVulkanTextureData);
- data->image = image;
- data->texture = texture;
- data->renderer = self;
-
- if (gdk_texture_set_render_data (texture, self, data, gsk_vulkan_renderer_clear_texture))
- {
- g_object_ref (data->image);
- self->textures = g_slist_prepend (self->textures, data);
- }
- else
- {
- g_slice_free (GskVulkanTextureData, data);
- }
-
- return image;
-}
-
-guint
-gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
- PangoFont *font,
- PangoGlyph glyph,
- float scale)
-{
- return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, scale)->texture_index;
-}
-
-GskVulkanImage *
-gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
- GskVulkanUploader *uploader,
- guint index)
-{
- return g_object_ref (gsk_vulkan_glyph_cache_get_glyph_image (self->glyph_cache, uploader, index));
-}
-
-GskVulkanCachedGlyph *
-gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
- PangoFont *font,
- PangoGlyph glyph,
- float scale)
-{
- return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, scale);
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_RENDERER_PRIVATE_H__
-#define __GSK_VULKAN_RENDERER_PRIVATE_H__
-
-#include <vulkan/vulkan.h>
-#include <gsk/gskrenderer.h>
-
-#include "gsk/gskvulkanimageprivate.h"
-
-G_BEGIN_DECLS
-
-#define GSK_TYPE_VULKAN_RENDERER (gsk_vulkan_renderer_get_type ())
-
-#define GSK_VULKAN_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRenderer))
-#define GSK_IS_VULKAN_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_VULKAN_RENDERER))
-#define GSK_VULKAN_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
-#define GSK_IS_VULKAN_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_VULKAN_RENDERER))
-#define GSK_VULKAN_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
-
-typedef struct _GskVulkanRenderer GskVulkanRenderer;
-typedef struct _GskVulkanRendererClass GskVulkanRendererClass;
-
-GType gsk_vulkan_renderer_get_type (void) G_GNUC_CONST;
-
-GskVulkanImage * gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
- GdkTexture *texture,
- GskVulkanUploader *uploader);
-
-typedef struct
-{
- guint texture_index;
-
- float tx;
- float ty;
- float tw;
- float th;
-
- int draw_x;
- int draw_y;
- int draw_width;
- int draw_height;
-
- guint64 timestamp;
-} GskVulkanCachedGlyph;
-
-guint gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *renderer,
- PangoFont *font,
- PangoGlyph glyph,
- float scale);
-
-GskVulkanImage * gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
- GskVulkanUploader *uploader,
- guint index);
-
-GskVulkanCachedGlyph * gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
- PangoFont *font,
- PangoGlyph glyph,
- float scale);
-
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_RENDERER_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanrenderpassprivate.h"
-
-#include "gskdebugprivate.h"
-#include "gskprofilerprivate.h"
-#include "gskrendernodeprivate.h"
-#include "gskrenderer.h"
-#include "gskrendererprivate.h"
-#include "gskroundedrectprivate.h"
-#include "gskvulkanblendmodepipelineprivate.h"
-#include "gskvulkanblurpipelineprivate.h"
-#include "gskvulkanborderpipelineprivate.h"
-#include "gskvulkanboxshadowpipelineprivate.h"
-#include "gskvulkanclipprivate.h"
-#include "gskvulkancolorpipelineprivate.h"
-#include "gskvulkancolortextpipelineprivate.h"
-#include "gskvulkancrossfadepipelineprivate.h"
-#include "gskvulkaneffectpipelineprivate.h"
-#include "gskvulkanlineargradientpipelineprivate.h"
-#include "gskvulkantextpipelineprivate.h"
-#include "gskvulkantexturepipelineprivate.h"
-#include "gskvulkanimageprivate.h"
-#include "gskvulkanpushconstantsprivate.h"
-#include "gskvulkanrendererprivate.h"
-#include "gskprivate.h"
-
-#include <cairo-ft.h>
-
-#define ORTHO_NEAR_PLANE -10000
-#define ORTHO_FAR_PLANE 10000
-
-typedef union _GskVulkanOp GskVulkanOp;
-typedef struct _GskVulkanOpRender GskVulkanOpRender;
-typedef struct _GskVulkanOpText GskVulkanOpText;
-typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants;
-
-typedef enum {
- /* GskVulkanOpRender */
- GSK_VULKAN_OP_FALLBACK,
- GSK_VULKAN_OP_FALLBACK_CLIP,
- GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP,
- GSK_VULKAN_OP_SURFACE,
- GSK_VULKAN_OP_TEXTURE,
- GSK_VULKAN_OP_COLOR,
- GSK_VULKAN_OP_LINEAR_GRADIENT,
- GSK_VULKAN_OP_OPACITY,
- GSK_VULKAN_OP_BLUR,
- GSK_VULKAN_OP_COLOR_MATRIX,
- GSK_VULKAN_OP_BORDER,
- GSK_VULKAN_OP_INSET_SHADOW,
- GSK_VULKAN_OP_OUTSET_SHADOW,
- GSK_VULKAN_OP_REPEAT,
- GSK_VULKAN_OP_CROSS_FADE,
- GSK_VULKAN_OP_BLEND_MODE,
- /* GskVulkanOpText */
- GSK_VULKAN_OP_TEXT,
- GSK_VULKAN_OP_COLOR_TEXT,
- /* GskVulkanOpPushConstants */
- GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS,
-} GskVulkanOpType;
-
-/* render ops with 0, 1 or 2 sources */
-struct _GskVulkanOpRender
-{
- GskVulkanOpType type;
- GskRenderNode *node; /* node that's the source of this op */
- GskVulkanPipeline *pipeline; /* pipeline to use */
- GskRoundedRect clip; /* clip rect (or random memory if not relevant) */
- GskVulkanImage *source; /* source image to render */
- GskVulkanImage *source2; /* second source image to render (if relevant) */
- gsize vertex_offset; /* offset into vertex buffer */
- gsize vertex_count; /* number of vertices */
- gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
- gsize descriptor_set_index2; /* descriptor index for the second source (if relevant) */
- graphene_rect_t source_rect; /* area that source maps to */
- graphene_rect_t source2_rect; /* area that source2 maps to */
-};
-
-struct _GskVulkanOpText
-{
- GskVulkanOpType type;
- GskRenderNode *node; /* node that's the source of this op */
- GskVulkanPipeline *pipeline; /* pipeline to use */
- GskRoundedRect clip; /* clip rect (or random memory if not relevant) */
- GskVulkanImage *source; /* source image to render */
- gsize vertex_offset; /* offset into vertex buffer */
- gsize vertex_count; /* number of vertices */
- gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
- guint texture_index; /* index of the texture in the glyph cache */
- guint start_glyph; /* the first glyph in nodes glyphstring that we render */
- guint num_glyphs; /* number of *non-empty* glyphs (== instances) we render */
- float scale;
-};
-
-struct _GskVulkanOpPushConstants
-{
- GskVulkanOpType type;
- GskRenderNode *node; /* node that's the source of this op */
- GskVulkanPushConstants constants; /* new constants to push */
-};
-
-union _GskVulkanOp
-{
- GskVulkanOpType type;
- GskVulkanOpRender render;
- GskVulkanOpText text;
- GskVulkanOpPushConstants constants;
-};
-
-struct _GskVulkanRenderPass
-{
- GdkVulkanContext *vulkan;
-
- GArray *render_ops;
-
- GskVulkanImage *target;
- int scale_factor;
- graphene_rect_t viewport;
- cairo_region_t *clip;
- graphene_matrix_t mv;
- graphene_matrix_t p;
-
- VkRenderPass render_pass;
- VkSemaphore signal_semaphore;
- GArray *wait_semaphores;
- GskVulkanBuffer *vertex_data;
-
- GQuark fallback_pixels;
- GQuark texture_pixels;
-};
-
-GskVulkanRenderPass *
-gsk_vulkan_render_pass_new (GdkVulkanContext *context,
- GskVulkanImage *target,
- int scale_factor,
- graphene_matrix_t *mv,
- graphene_rect_t *viewport,
- cairo_region_t *clip,
- VkSemaphore signal_semaphore)
-{
- GskVulkanRenderPass *self;
- VkImageLayout final_layout;
-
- self = g_slice_new0 (GskVulkanRenderPass);
- self->vulkan = g_object_ref (context);
- self->render_ops = g_array_new (FALSE, FALSE, sizeof (GskVulkanOp));
-
- self->target = g_object_ref (target);
- self->scale_factor = scale_factor;
- self->clip = cairo_region_copy (clip);
- self->viewport = *viewport;
-
- self->mv = *mv;
- graphene_matrix_init_ortho (&self->p,
- viewport->origin.x, viewport->origin.x + viewport->size.width,
- viewport->origin.y, viewport->origin.y + viewport->size.height,
- ORTHO_NEAR_PLANE,
- ORTHO_FAR_PLANE);
-
- if (signal_semaphore != VK_NULL_HANDLE) // this is a dependent pass
- final_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- else
- final_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
- GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
- &(VkRenderPassCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
- .attachmentCount = 1,
- .pAttachments = (VkAttachmentDescription[]) {
- {
- .format = gdk_vulkan_context_get_image_format (self->vulkan),
- .samples = VK_SAMPLE_COUNT_1_BIT,
- .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
- .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
- .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
- .finalLayout = final_layout
- }
- },
- .subpassCount = 1,
- .pSubpasses = (VkSubpassDescription []) {
- {
- .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
- .inputAttachmentCount = 0,
- .colorAttachmentCount = 1,
- .pColorAttachments = (VkAttachmentReference []) {
- {
- .attachment = 0,
- .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
- }
- },
- .pResolveAttachments = (VkAttachmentReference []) {
- {
- .attachment = VK_ATTACHMENT_UNUSED,
- .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
- }
- },
- .pDepthStencilAttachment = NULL,
- }
- },
- .dependencyCount = 0
- },
- NULL,
- &self->render_pass);
-
- self->signal_semaphore = signal_semaphore;
- self->wait_semaphores = g_array_new (FALSE, FALSE, sizeof (VkSemaphore));
- self->vertex_data = NULL;
-
-#ifdef G_ENABLE_DEBUG
- self->fallback_pixels = g_quark_from_static_string ("fallback-pixels");
- self->texture_pixels = g_quark_from_static_string ("texture-pixels");
-#endif
-
- return self;
-}
-
-void
-gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
-{
- g_array_unref (self->render_ops);
- g_object_unref (self->vulkan);
- g_object_unref (self->target);
- cairo_region_destroy (self->clip);
- vkDestroyRenderPass (gdk_vulkan_context_get_device (self->vulkan),
- self->render_pass,
- NULL);
- if (self->vertex_data)
- gsk_vulkan_buffer_free (self->vertex_data);
- if (self->signal_semaphore != VK_NULL_HANDLE)
- vkDestroySemaphore (gdk_vulkan_context_get_device (self->vulkan),
- self->signal_semaphore,
- NULL);
- g_array_unref (self->wait_semaphores);
-
-
- g_slice_free (GskVulkanRenderPass, self);
-}
-
-static gboolean
-font_has_color_glyphs (const PangoFont *font)
-{
- cairo_scaled_font_t *scaled_font;
- gboolean has_color = FALSE;
-
- scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
- if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT)
- {
- FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
- has_color = (FT_HAS_COLOR (ft_face) != 0);
- cairo_ft_scaled_font_unlock_face (scaled_font);
- }
-
- return has_color;
-}
-
-#define FALLBACK(...) G_STMT_START { \
- GSK_NOTE (FALLBACK, g_print (__VA_ARGS__)); \
- goto fallback; \
-}G_STMT_END
-
-static void
-gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- const GskVulkanPushConstants *constants,
- GskRenderNode *node)
-{
- GskVulkanOp op = {
- .type = GSK_VULKAN_OP_FALLBACK,
- .render.node = node
- };
- GskVulkanPipelineType pipeline_type;
-
- switch (gsk_render_node_get_node_type (node))
- {
- case GSK_NOT_A_RENDER_NODE:
- g_assert_not_reached ();
- return;
- case GSK_SHADOW_NODE:
- default:
- FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name);
-
- case GSK_REPEAT_NODE:
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
- else
- FALLBACK ("Repeat nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_REPEAT;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_BLEND_NODE:
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED;
- else
- FALLBACK ("Blend nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_BLEND_MODE;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_CROSS_FADE_NODE:
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED;
- else
- FALLBACK ("Cross fade nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_CROSS_FADE;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_INSET_SHADOW_NODE:
- if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
- FALLBACK ("Blur support not implemented for inset shadows\n");
- else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED;
- else
- FALLBACK ("Inset shadow nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_INSET_SHADOW;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_OUTSET_SHADOW_NODE:
- if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
- FALLBACK ("Blur support not implemented for outset shadows\n");
- else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED;
- else
- FALLBACK ("Outset shadow nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_OUTSET_SHADOW;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_CAIRO_NODE:
- if (gsk_cairo_node_peek_surface (node) == NULL)
- return;
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
- else
- FALLBACK ("Cairo nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_SURFACE;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_TEXT_NODE:
- {
- const PangoFont *font = gsk_text_node_peek_font (node);
- const PangoGlyphInfo *glyphs = gsk_text_node_peek_glyphs (node);
- guint num_glyphs = gsk_text_node_get_num_glyphs (node);
- int i;
- guint count;
- guint texture_index;
- GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render));
-
- if (font_has_color_glyphs (font))
- {
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED;
- else
- FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_COLOR_TEXT;
- }
- else
- {
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_TEXT;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
- else
- FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_TEXT;
- }
- op.text.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
-
- op.text.start_glyph = 0;
- op.text.texture_index = G_MAXUINT;
- op.text.scale = self->scale_factor;
-
- for (i = 0, count = 0; i < num_glyphs; i++)
- {
- const PangoGlyphInfo *gi = &glyphs[i];
-
- texture_index = gsk_vulkan_renderer_cache_glyph (renderer, (PangoFont *)font, gi->glyph, op.text.scale);
- if (op.text.texture_index == G_MAXUINT)
- op.text.texture_index = texture_index;
- if (texture_index != op.text.texture_index)
- {
- op.text.num_glyphs = count;
-
- g_array_append_val (self->render_ops, op);
-
- count = 1;
- op.text.start_glyph = i;
- op.text.texture_index = texture_index;
- }
- else
- count++;
- }
-
- if (op.text.texture_index != G_MAXUINT && count != 0)
- {
- op.text.num_glyphs = count;
- g_array_append_val (self->render_ops, op);
- }
-
- return;
- }
-
- case GSK_TEXTURE_NODE:
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
- else
- FALLBACK ("Texture nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_TEXTURE;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_COLOR_NODE:
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED;
- else
- FALLBACK ("Color nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_COLOR;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_LINEAR_GRADIENT_NODE:
- case GSK_REPEATING_LINEAR_GRADIENT_NODE:
- if (gsk_linear_gradient_node_get_n_color_stops (node) > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
- FALLBACK ("Linear gradient with %zu color stops, hardcoded limit is %u\n",
- gsk_linear_gradient_node_get_n_color_stops (node),
- GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED;
- else
- FALLBACK ("Linear gradient nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_LINEAR_GRADIENT;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_OPACITY_NODE:
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
- else
- FALLBACK ("Opacity nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_OPACITY;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_BLUR_NODE:
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_BLUR;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED;
- else
- FALLBACK ("Blur nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_BLUR;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_COLOR_MATRIX_NODE:
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
- else
- FALLBACK ("Color matrix nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_COLOR_MATRIX;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_BORDER_NODE:
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_BORDER;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED;
- else
- FALLBACK ("Border nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_BORDER;
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
-
- case GSK_CONTAINER_NODE:
- {
- guint i;
-
- for (i = 0; i < gsk_container_node_get_n_children (node); i++)
- {
- gsk_vulkan_render_pass_add_node (self, render, constants, gsk_container_node_get_child (node, i));
- }
- }
- return;
-
- case GSK_TRANSFORM_NODE:
- {
- graphene_matrix_t transform, mv;
- GskRenderNode *child;
-
-#if 0
- if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
- FALLBACK ("Transform nodes can't deal with clip type %u\n", clip->type);
-#endif
-
- graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
- graphene_matrix_init_from_matrix (&mv, &self->mv);
- graphene_matrix_multiply (&transform, &mv, &self->mv);
- child = gsk_transform_node_get_child (node);
- if (!gsk_vulkan_push_constants_transform (&op.constants.constants, constants, &transform, &child->bounds))
- FALLBACK ("Transform nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
- g_array_append_val (self->render_ops, op);
-
- gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, child);
- gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
- graphene_matrix_init_from_matrix (&self->mv, &mv);
- g_array_append_val (self->render_ops, op);
- }
- return;
-
- case GSK_CLIP_NODE:
- {
- if (!gsk_vulkan_push_constants_intersect_rect (&op.constants.constants, constants, gsk_clip_node_peek_clip (node)))
- FALLBACK ("Failed to find intersection between clip of type %u and rectangle\n", constants->clip.type);
- if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
- return;
-
- op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
- g_array_append_val (self->render_ops, op);
-
- gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_clip_node_get_child (node));
-
- gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
- g_array_append_val (self->render_ops, op);
- }
- return;
-
- case GSK_ROUNDED_CLIP_NODE:
- {
- if (!gsk_vulkan_push_constants_intersect_rounded (&op.constants.constants,
- constants,
- gsk_rounded_clip_node_peek_clip (node)))
- FALLBACK ("Failed to find intersection between clip of type %u and rounded rectangle\n", constants->clip.type);
- if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
- return;
-
- op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
- g_array_append_val (self->render_ops, op);
-
- gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_rounded_clip_node_get_child (node));
-
- gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
- g_array_append_val (self->render_ops, op);
- }
- return;
- }
-
- g_assert_not_reached ();
- return;
-
-fallback:
- switch (constants->clip.type)
- {
- case GSK_VULKAN_CLIP_NONE:
- op.type = GSK_VULKAN_OP_FALLBACK;
- break;
- case GSK_VULKAN_CLIP_RECT:
- op.type = GSK_VULKAN_OP_FALLBACK_CLIP;
- gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
- break;
- case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
- case GSK_VULKAN_CLIP_ROUNDED:
- op.type = GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP;
- gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
- break;
- case GSK_VULKAN_CLIP_ALL_CLIPPED:
- default:
- g_assert_not_reached ();
- return;
- }
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_TEXTURE);
- g_array_append_val (self->render_ops, op);
-}
-#undef FALLBACK
-
-void
-gsk_vulkan_render_pass_add (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- GskRenderNode *node)
-{
- GskVulkanOp op = { 0, };
- graphene_matrix_t mvp;
-
- graphene_matrix_multiply (&self->mv, &self->p, &mvp);
- op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
- gsk_vulkan_push_constants_init (&op.constants.constants, &mvp, &self->viewport);
- g_array_append_val (self->render_ops, op);
-
- gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, node);
-}
-
-static GskVulkanImage *
-gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- GskVulkanUploader *uploader,
- GskRenderNode *node,
- const graphene_rect_t *bounds,
- GskVulkanClip *current_clip,
- graphene_rect_t *tex_rect)
-{
- GskVulkanImage *result;
- cairo_surface_t *surface;
- cairo_t *cr;
-
- switch ((guint) gsk_render_node_get_node_type (node))
- {
- case GSK_TEXTURE_NODE:
- if (graphene_rect_equal (bounds, &node->bounds))
- {
- result = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
- gsk_texture_node_get_texture (node),
- uploader);
- gsk_vulkan_render_add_cleanup_image (render, result);
- *tex_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
- return result;
- }
- break;
-
- case GSK_CAIRO_NODE:
- if (graphene_rect_equal (bounds, &node->bounds))
- {
- surface = cairo_surface_reference ((cairo_surface_t *)gsk_cairo_node_peek_surface (node));
- goto got_surface;
- }
- break;
-
- default:
- {
- VkSemaphore semaphore;
- graphene_rect_t view;
- cairo_region_t *clip;
- GskVulkanRenderPass *pass;
- graphene_rect_t clipped;
-
- if (current_clip)
- graphene_rect_intersection (¤t_clip->rect.bounds, bounds, &clipped);
- else
- clipped = *bounds;
-
- if (clipped.size.width == 0 || clipped.size.height == 0)
- return NULL;
-
- graphene_matrix_transform_bounds (&self->mv, &clipped, &view);
- view.origin.x = floor (view.origin.x);
- view.origin.y = floor (view.origin.y);
- view.size.width = ceil (view.size.width);
- view.size.height = ceil (view.size.height);
-
- result = gsk_vulkan_image_new_for_texture (self->vulkan,
- view.size.width,
- view.size.height);
-
-#ifdef G_ENABLE_DEBUG
- {
- GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
- gsk_profiler_counter_add (profiler,
- self->texture_pixels,
- view.size.width * view.size.height);
- }
-#endif
-
- vkCreateSemaphore (gdk_vulkan_context_get_device (self->vulkan),
- &(VkSemaphoreCreateInfo) {
- VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
- NULL,
- 0
- },
- NULL,
- &semaphore);
-
- g_array_append_val (self->wait_semaphores, semaphore);
-
- clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
- 0, 0,
- gsk_vulkan_image_get_width (result),
- gsk_vulkan_image_get_height (result)
- });
-
- pass = gsk_vulkan_render_pass_new (self->vulkan,
- result,
- self->scale_factor,
- &self->mv,
- &view,
- clip,
- semaphore);
-
- cairo_region_destroy (clip);
-
- gsk_vulkan_render_add_render_pass (render, pass);
- gsk_vulkan_render_pass_add (pass, render, node);
- gsk_vulkan_render_add_cleanup_image (render, result);
-
- /* assuming the unclipped bounds should go to texture coordinates 0..1,
- * calculate the coordinates for the clipped texture size
- */
- tex_rect->origin.x = (bounds->origin.x - clipped.origin.x)/clipped.size.width;
- tex_rect->origin.y = (bounds->origin.y - clipped.origin.y)/clipped.size.height;
- tex_rect->size.width = bounds->size.width/clipped.size.width;
- tex_rect->size.height = bounds->size.height/clipped.size.height;
-
- return result;
- }
- }
-
- GSK_NOTE (FALLBACK, g_print ("Node as texture not implemented for this case. Using %gx%g fallback surface\n",
- ceil (bounds->size.width),
- ceil (bounds->size.height)));
-#ifdef G_ENABLE_DEBUG
- {
- GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
- gsk_profiler_counter_add (profiler,
- self->fallback_pixels,
- ceil (bounds->size.width) * ceil (bounds->size.height));
- }
-#endif
-
- /* XXX: We could intersect bounds with clip bounds here */
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- ceil (bounds->size.width),
- ceil (bounds->size.height));
- cr = cairo_create (surface);
- cairo_translate (cr, -bounds->origin.x, -bounds->origin.y);
-
- gsk_render_node_draw (node, cr);
-
- cairo_destroy (cr);
-
-got_surface:
- result = gsk_vulkan_image_new_from_data (uploader,
- cairo_image_surface_get_data (surface),
- cairo_image_surface_get_width (surface),
- cairo_image_surface_get_height (surface),
- cairo_image_surface_get_stride (surface));
-
- cairo_surface_destroy (surface);
-
- gsk_vulkan_render_add_cleanup_image (render, result);
-
- tex_rect->origin.x = (node->bounds.origin.x - bounds->origin.x)/bounds->size.width;
- tex_rect->origin.y = (node->bounds.origin.y - bounds->origin.y)/bounds->size.height;
- tex_rect->size.width = node->bounds.size.width/bounds->size.width;
- tex_rect->size.height = node->bounds.size.height/bounds->size.height;
-
- return result;
-}
-
-static void
-gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self,
- GskVulkanOpRender *op,
- GskVulkanRender *render,
- GskVulkanUploader *uploader)
-{
- GskRenderNode *node;
- cairo_surface_t *surface;
- cairo_t *cr;
-
- node = op->node;
-
- GSK_NOTE (FALLBACK,
- g_print ("Upload op=%s, node %s[%p], bounds %gx%g\n",
- op->type == GSK_VULKAN_OP_FALLBACK_CLIP ? "fallback-clip" :
- (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP ? "fallback-rounded-clip" : "fallback"),
- node->name ? node->name : node->node_class->type_name, node,
- ceil (node->bounds.size.width),
- ceil (node->bounds.size.height)));
-#ifdef G_ENABLE_DEBUG
- {
- GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
- gsk_profiler_counter_add (profiler,
- self->fallback_pixels,
- ceil (node->bounds.size.width) * ceil (node->bounds.size.height));
- }
-#endif
-
- /* XXX: We could intersect bounds with clip bounds here */
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- ceil (node->bounds.size.width * self->scale_factor),
- ceil (node->bounds.size.height * self->scale_factor));
- cairo_surface_set_device_scale (surface, self->scale_factor, self->scale_factor);
- cr = cairo_create (surface);
- cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
-
- if (op->type == GSK_VULKAN_OP_FALLBACK_CLIP)
- {
- cairo_rectangle (cr,
- op->clip.bounds.origin.x, op->clip.bounds.origin.y,
- op->clip.bounds.size.width, op->clip.bounds.size.height);
- cairo_clip (cr);
- }
- else if (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP)
- {
- gsk_rounded_rect_path (&op->clip, cr);
- cairo_clip (cr);
- }
- else
- {
- g_assert (op->type == GSK_VULKAN_OP_FALLBACK);
- }
-
- gsk_render_node_draw (node, cr);
-
- cairo_destroy (cr);
-
- op->source = gsk_vulkan_image_new_from_data (uploader,
- cairo_image_surface_get_data (surface),
- cairo_image_surface_get_width (surface),
- cairo_image_surface_get_height (surface),
- cairo_image_surface_get_stride (surface));
-
- op->source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
-
- cairo_surface_destroy (surface);
-
- gsk_vulkan_render_add_cleanup_image (render, op->source);
-}
-
-void
-gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- GskVulkanUploader *uploader)
-{
- GskVulkanOp *op;
- guint i;
- GskVulkanClip *clip = NULL;
-
- for (i = 0; i < self->render_ops->len; i++)
- {
- op = &g_array_index (self->render_ops, GskVulkanOp, i);
-
- switch (op->type)
- {
- case GSK_VULKAN_OP_FALLBACK:
- case GSK_VULKAN_OP_FALLBACK_CLIP:
- case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
- gsk_vulkan_render_pass_upload_fallback (self, &op->render, render, uploader);
- break;
-
- case GSK_VULKAN_OP_SURFACE:
- {
- cairo_surface_t *surface;
-
- surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (op->render.node);
- op->render.source = gsk_vulkan_image_new_from_data (uploader,
- cairo_image_surface_get_data (surface),
- cairo_image_surface_get_width (surface),
- cairo_image_surface_get_height (surface),
- cairo_image_surface_get_stride (surface));
- op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
-
- gsk_vulkan_render_add_cleanup_image (render, op->render.source);
- }
- break;
-
- case GSK_VULKAN_OP_TEXT:
- case GSK_VULKAN_OP_COLOR_TEXT:
- {
- op->text.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
- uploader,
- op->text.texture_index);
- gsk_vulkan_render_add_cleanup_image (render, op->text.source);
- }
- break;
-
- case GSK_VULKAN_OP_TEXTURE:
- {
- op->render.source = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
- gsk_texture_node_get_texture (op->render.node),
- uploader);
- op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
- gsk_vulkan_render_add_cleanup_image (render, op->render.source);
- }
- break;
-
- case GSK_VULKAN_OP_OPACITY:
- {
- GskRenderNode *child = gsk_opacity_node_get_child (op->render.node);
-
- op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
- render,
- uploader,
- child,
- &child->bounds,
- clip,
- &op->render.source_rect);
- }
- break;
-
- case GSK_VULKAN_OP_REPEAT:
- {
- GskRenderNode *child = gsk_repeat_node_get_child (op->render.node);
- const graphene_rect_t *bounds = &op->render.node->bounds;
- const graphene_rect_t *child_bounds = gsk_repeat_node_peek_child_bounds (op->render.node);
-
- op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
- render,
- uploader,
- child,
- child_bounds,
- NULL,
- &op->render.source_rect);
-
- op->render.source_rect.origin.x = (bounds->origin.x - child_bounds->origin.x)/child_bounds->size.width;
- op->render.source_rect.origin.y = (bounds->origin.y - child_bounds->origin.y)/child_bounds->size.height;
- op->render.source_rect.size.width = bounds->size.width / child_bounds->size.width;
- op->render.source_rect.size.height = bounds->size.height / child_bounds->size.height;
- }
- break;
-
- case GSK_VULKAN_OP_BLUR:
- {
- GskRenderNode *child = gsk_blur_node_get_child (op->render.node);
-
- op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
- render,
- uploader,
- child,
- &child->bounds,
- clip,
- &op->render.source_rect);
- }
- break;
-
- case GSK_VULKAN_OP_COLOR_MATRIX:
- {
- GskRenderNode *child = gsk_color_matrix_node_get_child (op->render.node);
-
- op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
- render,
- uploader,
- child,
- &child->bounds,
- clip,
- &op->render.source_rect);
- }
- break;
-
- case GSK_VULKAN_OP_CROSS_FADE:
- {
- GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->render.node);
- GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->render.node);
- const graphene_rect_t *bounds = &op->render.node->bounds;
-
- op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
- render,
- uploader,
- start,
- &start->bounds,
- clip,
- &op->render.source_rect);
- op->render.source_rect.origin.x = (bounds->origin.x - start->bounds.origin.x)/start->bounds.size.width;
- op->render.source_rect.origin.y = (bounds->origin.y - start->bounds.origin.y)/start->bounds.size.height;
- op->render.source_rect.size.width = bounds->size.width / start->bounds.size.width;
- op->render.source_rect.size.height = bounds->size.height / start->bounds.size.height;
-
- op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
- render,
- uploader,
- end,
- &end->bounds,
- clip,
- &op->render.source2_rect);
- op->render.source2_rect.origin.x = (bounds->origin.x - end->bounds.origin.x)/end->bounds.size.width;
- op->render.source2_rect.origin.y = (bounds->origin.y - end->bounds.origin.y)/end->bounds.size.height;
- op->render.source2_rect.size.width = bounds->size.width / end->bounds.size.width;
- op->render.source2_rect.size.height = bounds->size.height / end->bounds.size.height;
- }
- break;
-
- case GSK_VULKAN_OP_BLEND_MODE:
- {
- GskRenderNode *top = gsk_blend_node_get_top_child (op->render.node);
- GskRenderNode *bottom = gsk_blend_node_get_bottom_child (op->render.node);
- const graphene_rect_t *bounds = &op->render.node->bounds;
-
- op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
- render,
- uploader,
- top,
- &top->bounds,
- clip,
- &op->render.source_rect);
- op->render.source_rect.origin.x = (bounds->origin.x - top->bounds.origin.x)/top->bounds.size.width;
- op->render.source_rect.origin.y = (bounds->origin.y - top->bounds.origin.y)/top->bounds.size.height;
- op->render.source_rect.size.width = bounds->size.width / top->bounds.size.width;
- op->render.source_rect.size.height = bounds->size.height / top->bounds.size.height;
-
- op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
- render,
- uploader,
- bottom,
- &bottom->bounds,
- clip,
- &op->render.source2_rect);
- op->render.source2_rect.origin.x = (bounds->origin.x - bottom->bounds.origin.x)/bottom->bounds.size.width;
- op->render.source2_rect.origin.y = (bounds->origin.y - bottom->bounds.origin.y)/bottom->bounds.size.height;
- op->render.source2_rect.size.width = bounds->size.width / bottom->bounds.size.width;
- op->render.source2_rect.size.height = bounds->size.height / bottom->bounds.size.height;
- }
- break;
-
- case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
- clip = &op->constants.constants.clip;
- break;
-
- default:
- g_assert_not_reached ();
- case GSK_VULKAN_OP_COLOR:
- case GSK_VULKAN_OP_LINEAR_GRADIENT:
- case GSK_VULKAN_OP_BORDER:
- case GSK_VULKAN_OP_INSET_SHADOW:
- case GSK_VULKAN_OP_OUTSET_SHADOW:
- break;
- }
- }
-}
-
-static gsize
-gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
-{
- GskVulkanOp *op;
- gsize n_bytes;
- guint i;
-
- n_bytes = 0;
- for (i = 0; i < self->render_ops->len; i++)
- {
- op = &g_array_index (self->render_ops, GskVulkanOp, i);
-
- switch (op->type)
- {
- case GSK_VULKAN_OP_FALLBACK:
- case GSK_VULKAN_OP_FALLBACK_CLIP:
- case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
- case GSK_VULKAN_OP_SURFACE:
- case GSK_VULKAN_OP_TEXTURE:
- case GSK_VULKAN_OP_REPEAT:
- op->render.vertex_count = gsk_vulkan_texture_pipeline_count_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline));
- n_bytes += op->render.vertex_count;
- break;
-
- case GSK_VULKAN_OP_TEXT:
- op->text.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
- op->text.num_glyphs);
- n_bytes += op->text.vertex_count;
- break;
-
- case GSK_VULKAN_OP_COLOR_TEXT:
- op->text.vertex_count = gsk_vulkan_color_text_pipeline_count_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->render.pipeline),
- op->text.num_glyphs);
- n_bytes += op->text.vertex_count;
- break;
-
- case GSK_VULKAN_OP_COLOR:
- op->render.vertex_count = gsk_vulkan_color_pipeline_count_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline));
- n_bytes += op->render.vertex_count;
- break;
-
- case GSK_VULKAN_OP_LINEAR_GRADIENT:
- op->render.vertex_count = gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline));
- n_bytes += op->render.vertex_count;
- break;
-
- case GSK_VULKAN_OP_OPACITY:
- case GSK_VULKAN_OP_COLOR_MATRIX:
- op->render.vertex_count = gsk_vulkan_effect_pipeline_count_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline));
- n_bytes += op->render.vertex_count;
- break;
-
- case GSK_VULKAN_OP_BLUR:
- op->render.vertex_count = gsk_vulkan_blur_pipeline_count_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline));
- n_bytes += op->render.vertex_count;
- break;
-
- case GSK_VULKAN_OP_BORDER:
- op->render.vertex_count = gsk_vulkan_border_pipeline_count_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline));
- n_bytes += op->render.vertex_count;
- break;
-
- case GSK_VULKAN_OP_INSET_SHADOW:
- case GSK_VULKAN_OP_OUTSET_SHADOW:
- op->render.vertex_count = gsk_vulkan_box_shadow_pipeline_count_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline));
- n_bytes += op->render.vertex_count;
- break;
-
- case GSK_VULKAN_OP_CROSS_FADE:
- op->render.vertex_count = gsk_vulkan_cross_fade_pipeline_count_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline));
- n_bytes += op->render.vertex_count;
- break;
-
- case GSK_VULKAN_OP_BLEND_MODE:
- op->render.vertex_count = gsk_vulkan_blend_mode_pipeline_count_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline));
- n_bytes += op->render.vertex_count;
- break;
-
- default:
- g_assert_not_reached ();
-
- case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
- continue;
- }
- }
-
- return n_bytes;
-}
-
-static gsize
-gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- guchar *data,
- gsize offset,
- gsize total)
-{
- GskVulkanOp *op;
- gsize n_bytes;
- guint i;
-
- n_bytes = 0;
- for (i = 0; i < self->render_ops->len; i++)
- {
- op = &g_array_index (self->render_ops, GskVulkanOp, i);
-
- switch (op->type)
- {
- case GSK_VULKAN_OP_FALLBACK:
- case GSK_VULKAN_OP_FALLBACK_CLIP:
- case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
- case GSK_VULKAN_OP_SURFACE:
- case GSK_VULKAN_OP_TEXTURE:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- &op->render.node->bounds,
- &op->render.source_rect);
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_REPEAT:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- &op->render.node->bounds,
- &op->render.source_rect);
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_TEXT:
- {
- op->text.vertex_offset = offset + n_bytes;
- gsk_vulkan_text_pipeline_collect_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
- data + n_bytes + offset,
- GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
- &op->text.node->bounds,
- (PangoFont *)gsk_text_node_peek_font (op->text.node),
- gsk_text_node_get_num_glyphs (op->text.node),
- gsk_text_node_peek_glyphs (op->text.node),
- gsk_text_node_peek_color (op->text.node),
- gsk_text_node_get_x (op->text.node),
- gsk_text_node_get_y (op->text.node),
- op->text.start_glyph,
- op->text.num_glyphs,
- op->text.scale);
- n_bytes += op->text.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_COLOR_TEXT:
- {
- op->text.vertex_offset = offset + n_bytes;
- gsk_vulkan_color_text_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->text.pipeline),
- data + n_bytes + offset,
- GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
- &op->text.node->bounds,
- (PangoFont *)gsk_text_node_peek_font (op->text.node),
- gsk_text_node_get_num_glyphs (op->text.node),
- gsk_text_node_peek_glyphs (op->text.node),
- gsk_text_node_get_x (op->text.node),
- gsk_text_node_get_y (op->text.node),
- op->text.start_glyph,
- op->text.num_glyphs,
- op->text.scale);
- n_bytes += op->text.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_COLOR:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_color_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- &op->render.node->bounds,
- gsk_color_node_peek_color (op->render.node));
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_LINEAR_GRADIENT:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- &op->render.node->bounds,
- gsk_linear_gradient_node_peek_start (op->render.node),
- gsk_linear_gradient_node_peek_end (op->render.node),
- gsk_render_node_get_node_type (op->render.node) == GSK_REPEATING_LINEAR_GRADIENT_NODE,
- gsk_linear_gradient_node_get_n_color_stops (op->render.node),
- gsk_linear_gradient_node_peek_color_stops (op->render.node));
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_OPACITY:
- {
- graphene_matrix_t color_matrix;
- graphene_vec4_t color_offset;
-
- graphene_matrix_init_from_float (&color_matrix,
- (float[16]) {
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, gsk_opacity_node_get_opacity (op->render.node)
- });
- graphene_vec4_init (&color_offset, 0.0, 0.0, 0.0, 0.0);
- op->render.vertex_offset = offset + n_bytes;
-
- gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- &op->render.node->bounds,
- &op->render.source_rect,
- &color_matrix,
- &color_offset);
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_BLUR:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_blur_pipeline_collect_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- &op->render.node->bounds,
- &op->render.source_rect,
- gsk_blur_node_get_radius (op->render.node));
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_COLOR_MATRIX:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- &op->render.node->bounds,
- &op->render.source_rect,
- gsk_color_matrix_node_peek_color_matrix (op->render.node),
- gsk_color_matrix_node_peek_color_offset (op->render.node));
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_BORDER:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_border_pipeline_collect_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- gsk_border_node_peek_outline (op->render.node),
- gsk_border_node_peek_widths (op->render.node),
- gsk_border_node_peek_colors (op->render.node));
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_INSET_SHADOW:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- gsk_inset_shadow_node_peek_outline (op->render.node),
- gsk_inset_shadow_node_peek_color (op->render.node),
- gsk_inset_shadow_node_get_dx (op->render.node),
- gsk_inset_shadow_node_get_dy (op->render.node),
- gsk_inset_shadow_node_get_spread (op->render.node),
- gsk_inset_shadow_node_get_blur_radius (op->render.node));
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_OUTSET_SHADOW:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- gsk_outset_shadow_node_peek_outline (op->render.node),
- gsk_outset_shadow_node_peek_color (op->render.node),
- gsk_outset_shadow_node_get_dx (op->render.node),
- gsk_outset_shadow_node_get_dy (op->render.node),
- gsk_outset_shadow_node_get_spread (op->render.node),
- gsk_outset_shadow_node_get_blur_radius (op->render.node));
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_CROSS_FADE:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- &op->render.node->bounds,
- &op->render.source_rect,
- &op->render.source2_rect,
- gsk_cross_fade_node_get_progress (op->render.node));
- n_bytes += op->render.vertex_count;
- }
- break;
-
- case GSK_VULKAN_OP_BLEND_MODE:
- {
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline),
- data + n_bytes + offset,
- &op->render.node->bounds,
- &op->render.source_rect,
- &op->render.source2_rect,
- gsk_blend_node_get_blend_mode (op->render.node));
- n_bytes += op->render.vertex_count;
- }
- break;
-
- default:
- g_assert_not_reached ();
- case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
- continue;
- }
-
- g_assert (n_bytes + offset <= total);
- }
-
- return n_bytes;
-}
-
-static GskVulkanBuffer *
-gsk_vulkan_render_pass_get_vertex_data (GskVulkanRenderPass *self,
- GskVulkanRender *render)
-{
- if (self->vertex_data == NULL)
- {
- gsize n_bytes;
- guchar *data;
-
- n_bytes = gsk_vulkan_render_pass_count_vertex_data (self);
- self->vertex_data = gsk_vulkan_buffer_new (self->vulkan, n_bytes);
- data = gsk_vulkan_buffer_map (self->vertex_data);
- gsk_vulkan_render_pass_collect_vertex_data (self, render, data, 0, n_bytes);
- gsk_vulkan_buffer_unmap (self->vertex_data);
- }
-
- return self->vertex_data;
-}
-
-gsize
-gsk_vulkan_render_pass_get_wait_semaphores (GskVulkanRenderPass *self,
- VkSemaphore **semaphores)
-{
- *semaphores = (VkSemaphore *)self->wait_semaphores->data;
- return self->wait_semaphores->len;
-}
-
-gsize
-gsk_vulkan_render_pass_get_signal_semaphores (GskVulkanRenderPass *self,
- VkSemaphore **semaphores)
-{
- *semaphores = (VkSemaphore *)&self->signal_semaphore;
- return self->signal_semaphore != VK_NULL_HANDLE ? 1 : 0;
-}
-
-void
-gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
- GskVulkanRender *render)
-{
- GskVulkanOp *op;
- guint i;
-
- for (i = 0; i < self->render_ops->len; i++)
- {
- op = &g_array_index (self->render_ops, GskVulkanOp, i);
-
- switch (op->type)
- {
- case GSK_VULKAN_OP_FALLBACK:
- case GSK_VULKAN_OP_FALLBACK_CLIP:
- case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
- case GSK_VULKAN_OP_SURFACE:
- case GSK_VULKAN_OP_TEXTURE:
- case GSK_VULKAN_OP_OPACITY:
- case GSK_VULKAN_OP_BLUR:
- case GSK_VULKAN_OP_COLOR_MATRIX:
- if (op->render.source)
- op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
- break;
-
- case GSK_VULKAN_OP_REPEAT:
- if (op->render.source)
- op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, TRUE);
- break;
-
- case GSK_VULKAN_OP_TEXT:
- case GSK_VULKAN_OP_COLOR_TEXT:
- op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source, FALSE);
- break;
-
- case GSK_VULKAN_OP_CROSS_FADE:
- case GSK_VULKAN_OP_BLEND_MODE:
- if (op->render.source && op->render.source2)
- {
- op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
- op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE);
- }
- break;
-
- default:
- g_assert_not_reached ();
-
- case GSK_VULKAN_OP_COLOR:
- case GSK_VULKAN_OP_LINEAR_GRADIENT:
- case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
- case GSK_VULKAN_OP_BORDER:
- case GSK_VULKAN_OP_INSET_SHADOW:
- case GSK_VULKAN_OP_OUTSET_SHADOW:
- break;
- }
- }
-}
-
-static void
-gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- guint layout_count,
- VkPipelineLayout *pipeline_layout,
- VkCommandBuffer command_buffer)
-{
- GskVulkanPipeline *current_pipeline = NULL;
- gsize current_draw_index = 0;
- GskVulkanOp *op;
- guint i, step;
- GskVulkanBuffer *vertex_buffer;
-
- vertex_buffer = gsk_vulkan_render_pass_get_vertex_data (self, render);
-
- for (i = 0; i < self->render_ops->len; i += step)
- {
- op = &g_array_index (self->render_ops, GskVulkanOp, i);
- step = 1;
-
- switch (op->type)
- {
- case GSK_VULKAN_OP_FALLBACK:
- case GSK_VULKAN_OP_FALLBACK_CLIP:
- case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
- case GSK_VULKAN_OP_SURFACE:
- case GSK_VULKAN_OP_TEXTURE:
- case GSK_VULKAN_OP_REPEAT:
- if (!op->render.source)
- continue;
- if (current_pipeline != op->render.pipeline)
- {
- current_pipeline = op->render.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->render.vertex_offset });
- current_draw_index = 0;
- }
-
- vkCmdBindDescriptorSets (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
- 0,
- 1,
- (VkDescriptorSet[1]) {
- gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
- },
- 0,
- NULL);
-
- current_draw_index += gsk_vulkan_texture_pipeline_draw (GSK_VULKAN_TEXTURE_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, 1);
- break;
-
- case GSK_VULKAN_OP_TEXT:
- if (current_pipeline != op->text.pipeline)
- {
- current_pipeline = op->text.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->text.vertex_offset });
- current_draw_index = 0;
- }
-
- vkCmdBindDescriptorSets (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
- 0,
- 1,
- (VkDescriptorSet[1]) {
- gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
- },
- 0,
- NULL);
-
- current_draw_index += gsk_vulkan_text_pipeline_draw (GSK_VULKAN_TEXT_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, op->text.num_glyphs);
- break;
-
- case GSK_VULKAN_OP_COLOR_TEXT:
- if (current_pipeline != op->text.pipeline)
- {
- current_pipeline = op->text.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->text.vertex_offset });
- current_draw_index = 0;
- }
-
- vkCmdBindDescriptorSets (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
- 0,
- 1,
- (VkDescriptorSet[1]) {
- gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
- },
- 0,
- NULL);
-
- current_draw_index += gsk_vulkan_color_text_pipeline_draw (GSK_VULKAN_COLOR_TEXT_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, op->text.num_glyphs);
- break;
-
- case GSK_VULKAN_OP_OPACITY:
- case GSK_VULKAN_OP_COLOR_MATRIX:
- if (!op->render.source)
- continue;
- if (current_pipeline != op->render.pipeline)
- {
- current_pipeline = op->render.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->render.vertex_offset });
- current_draw_index = 0;
- }
-
- vkCmdBindDescriptorSets (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
- 0,
- 1,
- (VkDescriptorSet[1]) {
- gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
- },
- 0,
- NULL);
-
- current_draw_index += gsk_vulkan_effect_pipeline_draw (GSK_VULKAN_EFFECT_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, 1);
- break;
-
- case GSK_VULKAN_OP_BLUR:
- if (!op->render.source)
- continue;
- if (current_pipeline != op->render.pipeline)
- {
- current_pipeline = op->render.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->render.vertex_offset });
- current_draw_index = 0;
- }
-
- vkCmdBindDescriptorSets (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
- 0,
- 1,
- (VkDescriptorSet[1]) {
- gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
- },
- 0,
- NULL);
-
- current_draw_index += gsk_vulkan_blur_pipeline_draw (GSK_VULKAN_BLUR_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, 1);
- break;
-
- case GSK_VULKAN_OP_COLOR:
- if (current_pipeline != op->render.pipeline)
- {
- current_pipeline = op->render.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->render.vertex_offset });
- current_draw_index = 0;
- }
-
- for (step = 1; step + i < self->render_ops->len; step++)
- {
- GskVulkanOp *cmp = &g_array_index (self->render_ops, GskVulkanOp, i + step);
- if (cmp->type != GSK_VULKAN_OP_COLOR ||
- cmp->render.pipeline != current_pipeline)
- break;
- }
- current_draw_index += gsk_vulkan_color_pipeline_draw (GSK_VULKAN_COLOR_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, step);
- break;
-
- case GSK_VULKAN_OP_LINEAR_GRADIENT:
- if (current_pipeline != op->render.pipeline)
- {
- current_pipeline = op->render.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->render.vertex_offset });
- current_draw_index = 0;
- }
- current_draw_index += gsk_vulkan_linear_gradient_pipeline_draw (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, 1);
- break;
-
- case GSK_VULKAN_OP_BORDER:
- if (current_pipeline != op->render.pipeline)
- {
- current_pipeline = op->render.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->render.vertex_offset });
- current_draw_index = 0;
- }
- current_draw_index += gsk_vulkan_border_pipeline_draw (GSK_VULKAN_BORDER_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, 1);
- break;
-
- case GSK_VULKAN_OP_INSET_SHADOW:
- case GSK_VULKAN_OP_OUTSET_SHADOW:
- if (current_pipeline != op->render.pipeline)
- {
- current_pipeline = op->render.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->render.vertex_offset });
- current_draw_index = 0;
- }
- current_draw_index += gsk_vulkan_box_shadow_pipeline_draw (GSK_VULKAN_BOX_SHADOW_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, 1);
- break;
-
- case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
- for (int i = 0; i < layout_count; i++)
- gsk_vulkan_push_constants_push (&op->constants.constants,
- command_buffer,
- pipeline_layout[i]);
- break;
-
- case GSK_VULKAN_OP_CROSS_FADE:
- if (!op->render.source || !op->render.source2)
- continue;
- if (current_pipeline != op->render.pipeline)
- {
- current_pipeline = op->render.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->render.vertex_offset });
- current_draw_index = 0;
- }
-
- vkCmdBindDescriptorSets (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
- 0,
- 2,
- (VkDescriptorSet[2]) {
- gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
- gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
- },
- 0,
- NULL);
-
- current_draw_index += gsk_vulkan_cross_fade_pipeline_draw (GSK_VULKAN_CROSS_FADE_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, 1);
- break;
-
- case GSK_VULKAN_OP_BLEND_MODE:
- if (!op->render.source || !op->render.source2)
- continue;
- if (current_pipeline != op->render.pipeline)
- {
- current_pipeline = op->render.pipeline;
- vkCmdBindPipeline (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline (current_pipeline));
- vkCmdBindVertexBuffers (command_buffer,
- 0,
- 1,
- (VkBuffer[1]) {
- gsk_vulkan_buffer_get_buffer (vertex_buffer)
- },
- (VkDeviceSize[1]) { op->render.vertex_offset });
- current_draw_index = 0;
- }
-
- vkCmdBindDescriptorSets (command_buffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
- 0,
- 2,
- (VkDescriptorSet[2]) {
- gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
- gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
- },
- 0,
- NULL);
-
- current_draw_index += gsk_vulkan_blend_mode_pipeline_draw (GSK_VULKAN_BLEND_MODE_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, 1);
- break;
-
- default:
- g_assert_not_reached ();
- break;
- }
- }
-}
-
-void
-gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- guint layout_count,
- VkPipelineLayout *pipeline_layout,
- VkCommandBuffer command_buffer)
-{
- guint i;
-
- vkCmdSetViewport (command_buffer,
- 0,
- 1,
- &(VkViewport) {
- .x = 0,
- .y = 0,
- .width = self->viewport.size.width,
- .height = self->viewport.size.height,
- .minDepth = 0,
- .maxDepth = 1
- });
-
- for (i = 0; i < cairo_region_num_rectangles (self->clip); i++)
- {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (self->clip, i, &rect);
-
- vkCmdSetScissor (command_buffer,
- 0,
- 1,
- &(VkRect2D) {
- { rect.x * self->scale_factor, rect.y * self->scale_factor },
- { rect.width * self->scale_factor, rect.height * self->scale_factor }
- });
-
- vkCmdBeginRenderPass (command_buffer,
- &(VkRenderPassBeginInfo) {
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
- .renderPass = self->render_pass,
- .framebuffer = gsk_vulkan_render_get_framebuffer (render, self->target),
- .renderArea = {
- { rect.x * self->scale_factor, rect.y * self->scale_factor },
- { rect.width * self->scale_factor, rect.height * self->scale_factor }
- },
- .clearValueCount = 1,
- .pClearValues = (VkClearValue [1]) {
- { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
- }
- },
- VK_SUBPASS_CONTENTS_INLINE);
-
- gsk_vulkan_render_pass_draw_rect (self, render, layout_count, pipeline_layout, command_buffer);
-
- vkCmdEndRenderPass (command_buffer);
- }
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_RENDER_PASS_PRIVATE_H__
-#define __GSK_VULKAN_RENDER_PASS_PRIVATE_H__
-
-#include <gdk/gdk.h>
-#include <gsk/gskrendernode.h>
-
-#include "gsk/gskvulkanbufferprivate.h"
-#include "gsk/gskvulkanrenderprivate.h"
-#include "gsk/gskprivate.h"
-
-G_BEGIN_DECLS
-
-
-GskVulkanRenderPass * gsk_vulkan_render_pass_new (GdkVulkanContext *context,
- GskVulkanImage *target,
- int scale_factor,
- graphene_matrix_t *mv,
- graphene_rect_t *viewport,
- cairo_region_t *clip,
- VkSemaphore signal_semaphore);
-
-void gsk_vulkan_render_pass_free (GskVulkanRenderPass *self);
-
-void gsk_vulkan_render_pass_add (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- GskRenderNode *node);
-
-void gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- GskVulkanUploader *uploader);
-void gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
- GskVulkanRender *render);
-void gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
- GskVulkanRender *render,
- guint layout_count,
- VkPipelineLayout *pipeline_layout,
- VkCommandBuffer command_buffer);
-gsize gsk_vulkan_render_pass_get_wait_semaphores (GskVulkanRenderPass *self,
- VkSemaphore **semaphores);
-gsize gsk_vulkan_render_pass_get_signal_semaphores (GskVulkanRenderPass *self,
- VkSemaphore **semaphores);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_RENDER_PASS_PRIVATE_H__ */
+++ /dev/null
-#ifndef __GSK_VULKAN_RENDER_PRIVATE_H__
-#define __GSK_VULKAN_RENDER_PRIVATE_H__
-
-#include <gdk/gdk.h>
-#include <gsk/gskrendernode.h>
-
-#include "gsk/gskvulkanimageprivate.h"
-#include "gsk/gskvulkanpipelineprivate.h"
-#include "gsk/gskvulkanrenderpassprivate.h"
-#include "gsk/gskprivate.h"
-
-G_BEGIN_DECLS
-
-typedef enum {
- GSK_VULKAN_PIPELINE_TEXTURE,
- GSK_VULKAN_PIPELINE_TEXTURE_CLIP,
- GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_COLOR,
- GSK_VULKAN_PIPELINE_COLOR_CLIP,
- GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_LINEAR_GRADIENT,
- GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP,
- GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_COLOR_MATRIX,
- GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP,
- GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_BORDER,
- GSK_VULKAN_PIPELINE_BORDER_CLIP,
- GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_INSET_SHADOW,
- GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP,
- GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_OUTSET_SHADOW,
- GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP,
- GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_BLUR,
- GSK_VULKAN_PIPELINE_BLUR_CLIP,
- GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_TEXT,
- GSK_VULKAN_PIPELINE_TEXT_CLIP,
- GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_COLOR_TEXT,
- GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP,
- GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_CROSS_FADE,
- GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP,
- GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED,
- GSK_VULKAN_PIPELINE_BLEND_MODE,
- GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP,
- GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED,
- /* add more */
- GSK_VULKAN_N_PIPELINES
-} GskVulkanPipelineType;
-
-GskVulkanRender * gsk_vulkan_render_new (GskRenderer *renderer,
- GdkVulkanContext *context);
-void gsk_vulkan_render_free (GskVulkanRender *self);
-
-gboolean gsk_vulkan_render_is_busy (GskVulkanRender *self);
-void gsk_vulkan_render_reset (GskVulkanRender *self,
- GskVulkanImage *target,
- const graphene_rect_t *rect);
-
-GskRenderer * gsk_vulkan_render_get_renderer (GskVulkanRender *self);
-
-void gsk_vulkan_render_add_cleanup_image (GskVulkanRender *self,
- GskVulkanImage *image);
-
-void gsk_vulkan_render_add_node (GskVulkanRender *self,
- GskRenderNode *node);
-
-void gsk_vulkan_render_add_render_pass (GskVulkanRender *self,
- GskVulkanRenderPass *pass);
-
-void gsk_vulkan_render_upload (GskVulkanRender *self);
-
-GskVulkanPipeline * gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
- GskVulkanPipelineType pipeline_type);
-VkDescriptorSet gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
- gsize id);
-gsize gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
- GskVulkanImage *source,
- gboolean repeat);
-void gsk_vulkan_render_draw (GskVulkanRender *self);
-
-void gsk_vulkan_render_submit (GskVulkanRender *self);
-
-GdkTexture * gsk_vulkan_render_download_target (GskVulkanRender *self);
-VkFramebuffer gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
- GskVulkanImage *image);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_RENDER_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkanshaderprivate.h"
-#include "gskvulkanpipelineprivate.h"
-
-struct _GskVulkanShader
-{
- GdkVulkanContext *vulkan;
-
- GskVulkanShaderType type;
- VkShaderModule vk_shader;
-};
-
-static GskVulkanShader *
-gsk_vulkan_shader_new_from_bytes (GdkVulkanContext *context,
- GskVulkanShaderType type,
- GBytes *bytes,
- GError **error)
-{
- GskVulkanShader *self;
- VkShaderModule shader;
- VkResult res;
-
- res = GSK_VK_CHECK (vkCreateShaderModule, gdk_vulkan_context_get_device (context),
- &(VkShaderModuleCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
- .codeSize = g_bytes_get_size (bytes),
- .pCode = (uint32_t *) g_bytes_get_data (bytes, NULL),
- },
- NULL,
- &shader);
- if (res != VK_SUCCESS)
- {
- /* Someone invent better error categories plz */
- g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
- "Could not create shader: %s", gdk_vulkan_strerror (res));
- return NULL;
- }
-
- self = g_slice_new0 (GskVulkanShader);
-
- self->vulkan = g_object_ref (context);
- self->type = type;
- self->vk_shader = shader;
-
- return self;
-}
-
-GskVulkanShader *
-gsk_vulkan_shader_new_from_resource (GdkVulkanContext *context,
- GskVulkanShaderType type,
- const char *resource_name,
- GError **error)
-{
- GskVulkanShader *self;
- GBytes *bytes;
- GError *local_error = NULL;
- char *path;
-
- path = g_strconcat ("/org/gtk/libgsk/vulkan/",
- resource_name,
- type == GSK_VULKAN_SHADER_VERTEX ? ".vert.spv" : ".frag.spv",
- NULL);
- bytes = g_resources_lookup_data (path, 0, &local_error);
- g_free (path);
- if (bytes == NULL)
- {
- GSK_NOTE (VULKAN, g_printerr ("Error loading shader data: %s\n", local_error->message));
- g_propagate_error (error, local_error);
- return NULL;
- }
-
- self = gsk_vulkan_shader_new_from_bytes (context, type, bytes, error);
- g_bytes_unref (bytes);
-
- return self;
-}
-
-void
-gsk_vulkan_shader_free (GskVulkanShader *self)
-{
- vkDestroyShaderModule (gdk_vulkan_context_get_device (self->vulkan),
- self->vk_shader,
- NULL);
-
- g_object_unref (self->vulkan);
-
- g_slice_free (GskVulkanShader, self);
-}
-
-GskVulkanShaderType
-gsk_vulkan_shader_get_type (GskVulkanShader *shader)
-{
- return shader->type;
-}
-
-VkShaderModule
-gsk_vulkan_shader_get_module (GskVulkanShader *shader)
-{
- return shader->vk_shader;
-}
-
+++ /dev/null
-#ifndef __GSK_VULKAN_SHADER_PRIVATE_H__
-#define __GSK_VULKAN_SHADER_PRIVATE_H__
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-typedef enum {
- GSK_VULKAN_SHADER_VERTEX,
- GSK_VULKAN_SHADER_FRAGMENT
-} GskVulkanShaderType;
-
-typedef struct _GskVulkanShader GskVulkanShader;
-
-#define GST_VULKAN_SHADER_STAGE_CREATE_INFO(shader) \
- (VkPipelineShaderStageCreateInfo) { \
- .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, \
- .stage = gsk_vulkan_shader_get_type (shader) == GSK_VULKAN_SHADER_VERTEX ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, \
- .module = gsk_vulkan_shader_get_module (shader), \
- .pName = "main", \
-}
-
-GskVulkanShader * gsk_vulkan_shader_new_from_resource (GdkVulkanContext *context,
- GskVulkanShaderType type,
- const char *resource_name,
- GError **error);
-void gsk_vulkan_shader_free (GskVulkanShader *shader);
-
-GskVulkanShaderType gsk_vulkan_shader_get_type (GskVulkanShader *shader);
-VkShaderModule gsk_vulkan_shader_get_module (GskVulkanShader *shader);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_SHADER_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkantextpipelineprivate.h"
-
-struct _GskVulkanTextPipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanTextInstance GskVulkanTextInstance;
-
-struct _GskVulkanTextInstance
-{
- float rect[4];
- float tex_rect[4];
- float color[4];
-};
-
-G_DEFINE_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanTextInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, rect),
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, tex_rect),
- },
- {
- .location = 2,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, color),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_text_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanTextPipeline *self = GSK_VULKAN_TEXT_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_text_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_text_pipeline_class_init (GskVulkanTextPipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_text_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_text_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_text_pipeline_init (GskVulkanTextPipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_text_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_TEXT_PIPELINE, context, layout, shader_name, render_pass,
- VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
-}
-
-gsize
-gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
- int num_instances)
-{
- return sizeof (GskVulkanTextInstance) * num_instances;
-}
-
-void
-gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
- guchar *data,
- GskVulkanRenderer *renderer,
- const graphene_rect_t *rect,
- PangoFont *font,
- guint total_glyphs,
- const PangoGlyphInfo *glyphs,
- const GdkRGBA *color,
- float x,
- float y,
- guint start_glyph,
- guint num_glyphs,
- float scale)
-{
- GskVulkanTextInstance *instances = (GskVulkanTextInstance *) data;
- int i;
- int count = 0;
- int x_position = 0;
-
- for (i = 0; i < start_glyph; i++)
- x_position += glyphs[i].geometry.width;
-
- for (; i < total_glyphs && count < num_glyphs; i++)
- {
- const PangoGlyphInfo *gi = &glyphs[i];
-
- if (gi->glyph != PANGO_GLYPH_EMPTY)
- {
- double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
- double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
- GskVulkanTextInstance *instance = &instances[count];
- GskVulkanCachedGlyph *glyph;
-
- glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
-
- instance->tex_rect[0] = glyph->tx;
- instance->tex_rect[1] = glyph->ty;
- instance->tex_rect[2] = glyph->tw;
- instance->tex_rect[3] = glyph->th;
-
- instance->rect[0] = x + cx + glyph->draw_x;
- instance->rect[1] = y + cy + glyph->draw_y;
- instance->rect[2] = glyph->draw_width;
- instance->rect[3] = glyph->draw_height;
-
- instance->color[0] = color->red;
- instance->color[1] = color->green;
- instance->color[2] = color->blue;
- instance->color[3] = color->alpha;
-
- count++;
- }
- x_position += gi->geometry.width;
- }
-}
-
-gsize
-gsk_vulkan_text_pipeline_draw (GskVulkanTextPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-#include "gskvulkanrendererprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanTextPipelineLayout GskVulkanTextPipelineLayout;
-
-#define GSK_TYPE_VULKAN_TEXT_PIPELINE (gsk_vulkan_text_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK, VULKAN_TEXT_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_text_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
- int num_instances);
-void gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
- guchar *data,
- GskVulkanRenderer *renderer,
- const graphene_rect_t *rect,
- PangoFont *font,
- guint total_glyphs,
- const PangoGlyphInfo *glyphs,
- const GdkRGBA *color,
- float x,
- float y,
- guint start_glyph,
- guint num_glyphs,
- float scale);
-gsize gsk_vulkan_text_pipeline_draw (GskVulkanTextPipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__ */
+++ /dev/null
-#include "config.h"
-
-#include "gskvulkantexturepipelineprivate.h"
-
-struct _GskVulkanTexturePipeline
-{
- GObject parent_instance;
-};
-
-typedef struct _GskVulkanTextureInstance GskVulkanTextureInstance;
-
-struct _GskVulkanTextureInstance
-{
- float rect[4];
- float tex_rect[4];
-};
-
-G_DEFINE_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK_TYPE_VULKAN_PIPELINE)
-
-static const VkPipelineVertexInputStateCreateInfo *
-gsk_vulkan_texture_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
-{
- static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
- {
- .binding = 0,
- .stride = sizeof (GskVulkanTextureInstance),
- .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
- }
- };
- static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
- {
- .location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, rect),
- },
- {
- .location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
- .offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, tex_rect),
- }
- };
- static const VkPipelineVertexInputStateCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
- .pVertexBindingDescriptions = vertexBindingDescriptions,
- .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
- .pVertexAttributeDescriptions = vertexInputAttributeDescription
- };
-
- return &info;
-}
-
-static void
-gsk_vulkan_texture_pipeline_finalize (GObject *gobject)
-{
- //GskVulkanTexturePipeline *self = GSK_VULKAN_TEXTURE_PIPELINE (gobject);
-
- G_OBJECT_CLASS (gsk_vulkan_texture_pipeline_parent_class)->finalize (gobject);
-}
-
-static void
-gsk_vulkan_texture_pipeline_class_init (GskVulkanTexturePipelineClass *klass)
-{
- GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
-
- G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_texture_pipeline_finalize;
-
- pipeline_class->get_input_state_create_info = gsk_vulkan_texture_pipeline_get_input_state_create_info;
-}
-
-static void
-gsk_vulkan_texture_pipeline_init (GskVulkanTexturePipeline *self)
-{
-}
-
-GskVulkanPipeline *
-gsk_vulkan_texture_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass)
-{
- return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_TEXTURE_PIPELINE, context, layout, shader_name, render_pass);
-}
-
-gsize
-gsk_vulkan_texture_pipeline_count_vertex_data (GskVulkanTexturePipeline *pipeline)
-{
- return sizeof (GskVulkanTextureInstance);
-}
-
-void
-gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const graphene_rect_t *tex_rect)
-{
- GskVulkanTextureInstance *instance = (GskVulkanTextureInstance *) data;
-
- instance->rect[0] = rect->origin.x;
- instance->rect[1] = rect->origin.y;
- instance->rect[2] = rect->size.width;
- instance->rect[3] = rect->size.height;
- instance->tex_rect[0] = tex_rect->origin.x;
- instance->tex_rect[1] = tex_rect->origin.y;
- instance->tex_rect[2] = tex_rect->size.width;
- instance->tex_rect[3] = tex_rect->size.height;
-}
-
-gsize
-gsk_vulkan_texture_pipeline_draw (GskVulkanTexturePipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands)
-{
- vkCmdDraw (command_buffer,
- 6, n_commands,
- 0, offset);
-
- return n_commands;
-}
+++ /dev/null
-#ifndef __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__
-#define __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__
-
-#include <graphene.h>
-
-#include "gskvulkanpipelineprivate.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GskVulkanTexturePipelineLayout GskVulkanTexturePipelineLayout;
-
-#define GSK_TYPE_VULKAN_TEXTURE_PIPELINE (gsk_vulkan_texture_pipeline_get_type ())
-
-G_DECLARE_FINAL_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK, VULKAN_TEXTURE_PIPELINE, GskVulkanPipeline)
-
-GskVulkanPipeline * gsk_vulkan_texture_pipeline_new (GdkVulkanContext *context,
- VkPipelineLayout layout,
- const char *shader_name,
- VkRenderPass render_pass);
-
-gsize gsk_vulkan_texture_pipeline_count_vertex_data (GskVulkanTexturePipeline *pipeline);
-void gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
- guchar *data,
- const graphene_rect_t *rect,
- const graphene_rect_t *tex_rect);
-gsize gsk_vulkan_texture_pipeline_draw (GskVulkanTexturePipeline *pipeline,
- VkCommandBuffer command_buffer,
- gsize offset,
- gsize n_commands);
-
-G_END_DECLS
-
-#endif /* __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__ */
if have_vulkan
gsk_private_sources += files([
- 'gskvulkanblendmodepipeline.c',
- 'gskvulkanblurpipeline.c',
- 'gskvulkanborderpipeline.c',
- 'gskvulkanboxshadowpipeline.c',
- 'gskvulkanbuffer.c',
- 'gskvulkanclip.c',
- 'gskvulkancolorpipeline.c',
- 'gskvulkancolortextpipeline.c',
- 'gskvulkancrossfadepipeline.c',
- 'gskvulkancommandpool.c',
- 'gskvulkaneffectpipeline.c',
- 'gskvulkanglyphcache.c',
- 'gskvulkanlineargradientpipeline.c',
- 'gskvulkanimage.c',
- 'gskvulkantextpipeline.c',
- 'gskvulkantexturepipeline.c',
- 'gskvulkanmemory.c',
- 'gskvulkanpipeline.c',
- 'gskvulkanpushconstants.c',
- 'gskvulkanrender.c',
- 'gskvulkanrenderer.c',
- 'gskvulkanrenderpass.c',
- 'gskvulkanshader.c',
+ 'vulkan/gskvulkanblendmodepipeline.c',
+ 'vulkan/gskvulkanblurpipeline.c',
+ 'vulkan/gskvulkanborderpipeline.c',
+ 'vulkan/gskvulkanboxshadowpipeline.c',
+ 'vulkan/gskvulkanbuffer.c',
+ 'vulkan/gskvulkanclip.c',
+ 'vulkan/gskvulkancolorpipeline.c',
+ 'vulkan/gskvulkancolortextpipeline.c',
+ 'vulkan/gskvulkancrossfadepipeline.c',
+ 'vulkan/gskvulkancommandpool.c',
+ 'vulkan/gskvulkaneffectpipeline.c',
+ 'vulkan/gskvulkanglyphcache.c',
+ 'vulkan/gskvulkanlineargradientpipeline.c',
+ 'vulkan/gskvulkanimage.c',
+ 'vulkan/gskvulkantextpipeline.c',
+ 'vulkan/gskvulkantexturepipeline.c',
+ 'vulkan/gskvulkanmemory.c',
+ 'vulkan/gskvulkanpipeline.c',
+ 'vulkan/gskvulkanpushconstants.c',
+ 'vulkan/gskvulkanrender.c',
+ 'vulkan/gskvulkanrenderer.c',
+ 'vulkan/gskvulkanrenderpass.c',
+ 'vulkan/gskvulkanshader.c',
])
subdir('resources/vulkan')
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanblendmodepipelineprivate.h"
+
+struct _GskVulkanBlendModePipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanBlendModeInstance GskVulkanBlendModeInstance;
+
+struct _GskVulkanBlendModeInstance
+{
+ float rect[4];
+ float start_tex_rect[4];
+ float end_tex_rect[4];
+ guint32 blend_mode;
+};
+
+G_DEFINE_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_blend_mode_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanBlendModeInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = 0,
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, start_tex_rect),
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, end_tex_rect),
+ },
+ {
+ .location = 3,
+ .binding = 0,
+ .format = VK_FORMAT_R32_UINT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, blend_mode),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_blend_mode_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanBlendModePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_blend_mode_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_blend_mode_pipeline_class_init (GskVulkanBlendModePipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_blend_mode_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_blend_mode_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_blend_mode_pipeline_init (GskVulkanBlendModePipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_blend_mode_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline)
+{
+ return sizeof (GskVulkanBlendModeInstance);
+}
+
+void
+gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *bounds,
+ const graphene_rect_t *start_tex_rect,
+ const graphene_rect_t *end_tex_rect,
+ GskBlendMode blend_mode)
+{
+ GskVulkanBlendModeInstance *instance = (GskVulkanBlendModeInstance *) data;
+
+ instance->rect[0] = bounds->origin.x;
+ instance->rect[1] = bounds->origin.y;
+ instance->rect[2] = bounds->size.width;
+ instance->rect[3] = bounds->size.height;
+
+ instance->start_tex_rect[0] = start_tex_rect->origin.x;
+ instance->start_tex_rect[1] = start_tex_rect->origin.y;
+ instance->start_tex_rect[2] = start_tex_rect->size.width;
+ instance->start_tex_rect[3] = start_tex_rect->size.height;
+
+ instance->end_tex_rect[0] = end_tex_rect->origin.x;
+ instance->end_tex_rect[1] = end_tex_rect->origin.y;
+ instance->end_tex_rect[2] = end_tex_rect->size.width;
+ instance->end_tex_rect[3] = end_tex_rect->size.height;
+
+ instance->blend_mode = blend_mode;
+}
+
+gsize
+gsk_vulkan_blend_mode_pipeline_draw (GskVulkanBlendModePipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskenums.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBlendModePipelineLayout GskVulkanBlendModePipelineLayout;
+
+#define GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE (gsk_vulkan_blend_mode_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK, VULKAN_BLEND_MODE_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_blend_mode_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline);
+void gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *bounds,
+ const graphene_rect_t *start_bounds,
+ const graphene_rect_t *end_bounds,
+ GskBlendMode blend_mode);
+gsize gsk_vulkan_blend_mode_pipeline_draw (GskVulkanBlendModePipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BLEND_MODE_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanblurpipelineprivate.h"
+
+struct _GskVulkanBlurPipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanBlurInstance GskVulkanBlurInstance;
+
+struct _GskVulkanBlurInstance
+{
+ float rect[4];
+ float tex_rect[4];
+ float blur_radius;
+};
+
+G_DEFINE_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_blur_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanBlurInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = 0,
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, tex_rect),
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, blur_radius),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_blur_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanBlurPipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_blur_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_blur_pipeline_class_init (GskVulkanBlurPipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_blur_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_blur_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_blur_pipeline_init (GskVulkanBlurPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_blur_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLUR_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_blur_pipeline_count_vertex_data (GskVulkanBlurPipeline *pipeline)
+{
+ return sizeof (GskVulkanBlurInstance);
+}
+
+void
+gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const graphene_rect_t *tex_rect,
+ double blur_radius)
+{
+ GskVulkanBlurInstance *instance = (GskVulkanBlurInstance *) data;
+
+ instance->rect[0] = rect->origin.x;
+ instance->rect[1] = rect->origin.y;
+ instance->rect[2] = rect->size.width;
+ instance->rect[3] = rect->size.height;
+ instance->tex_rect[0] = tex_rect->origin.x;
+ instance->tex_rect[1] = tex_rect->origin.y;
+ instance->tex_rect[2] = tex_rect->size.width;
+ instance->tex_rect[3] = tex_rect->size.height;
+ instance->blur_radius = blur_radius;
+}
+
+gsize
+gsk_vulkan_blur_pipeline_draw (GskVulkanBlurPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBlurPipelineLayout GskVulkanBlurPipelineLayout;
+
+#define GSK_TYPE_VULKAN_BLUR_PIPELINE (gsk_vulkan_blur_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK, VULKAN_BLUR_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_blur_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_blur_pipeline_count_vertex_data (GskVulkanBlurPipeline *pipeline);
+void gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const graphene_rect_t *tex_rect,
+ double radius);
+gsize gsk_vulkan_blur_pipeline_draw (GskVulkanBlurPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BLUR_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanborderpipelineprivate.h"
+
+#include "gskroundedrectprivate.h"
+
+struct _GskVulkanBorderPipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanBorderInstance GskVulkanBorderInstance;
+
+struct _GskVulkanBorderInstance
+{
+ float rect[12];
+ float widths[4];
+ float colors[16];
+};
+
+G_DEFINE_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_border_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanBorderInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect),
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 4 * sizeof (float),
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 8 * sizeof (float),
+ },
+ {
+ .location = 3,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, widths),
+ },
+ {
+ .location = 4,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors),
+ },
+ {
+ .location = 5,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 4 * sizeof (float),
+ },
+ {
+ .location = 6,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 8 * sizeof (float),
+ },
+ {
+ .location = 7,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 12 * sizeof (float),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_border_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanBorderPipeline *self = GSK_VULKAN_BORDER_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_border_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_border_pipeline_class_init (GskVulkanBorderPipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_border_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_border_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_border_pipeline_init (GskVulkanBorderPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_border_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BORDER_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline)
+{
+ return sizeof (GskVulkanBorderInstance);
+}
+
+void
+gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
+ guchar *data,
+ const GskRoundedRect *rect,
+ const float widths[4],
+ const GdkRGBA colors[4])
+{
+ GskVulkanBorderInstance *instance = (GskVulkanBorderInstance *) data;
+ guint i;
+
+ gsk_rounded_rect_to_float (rect, instance->rect);
+ for (i = 0; i < 4; i++)
+ {
+ instance->widths[i] = widths[i];
+ instance->colors[4 * i + 0] = colors[i].red;
+ instance->colors[4 * i + 1] = colors[i].green;
+ instance->colors[4 * i + 2] = colors[i].blue;
+ instance->colors[4 * i + 3] = colors[i].alpha;
+ }
+}
+
+gsize
+gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6 * 8, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskroundedrect.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBorderPipelineLayout GskVulkanBorderPipelineLayout;
+
+#define GSK_TYPE_VULKAN_BORDER_PIPELINE (gsk_vulkan_border_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK, VULKAN_BORDER_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_border_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline);
+void gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
+ guchar *data,
+ const GskRoundedRect *rect,
+ const float widths[4],
+ const GdkRGBA colors[4]);
+gsize gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanboxshadowpipelineprivate.h"
+
+#include "gskroundedrectprivate.h"
+
+struct _GskVulkanBoxShadowPipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanBoxShadowInstance GskVulkanBoxShadowInstance;
+
+struct _GskVulkanBoxShadowInstance
+{
+ float outline[12];
+ float color[4];
+ float offset[2];
+ float spread;
+ float blur_radius;
+};
+
+G_DEFINE_TYPE (GskVulkanBoxShadowPipeline, gsk_vulkan_box_shadow_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_box_shadow_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanBoxShadowInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline),
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 4 * sizeof (float),
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 8 * sizeof (float),
+ },
+ {
+ .location = 3,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, color),
+ },
+ {
+ .location = 4,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, offset),
+ },
+ {
+ .location = 5,
+ .binding = 0,
+ .format = VK_FORMAT_R32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, spread),
+ },
+ {
+ .location = 6,
+ .binding = 0,
+ .format = VK_FORMAT_R32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, blur_radius),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_box_shadow_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanBoxShadowPipeline *self = GSK_VULKAN_BOX_SHADOW_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_box_shadow_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_box_shadow_pipeline_class_init (GskVulkanBoxShadowPipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_box_shadow_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_box_shadow_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_box_shadow_pipeline_init (GskVulkanBoxShadowPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_box_shadow_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BOX_SHADOW_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline *pipeline)
+{
+ return sizeof (GskVulkanBoxShadowInstance);
+}
+
+void
+gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *pipeline,
+ guchar *data,
+ const GskRoundedRect *outline,
+ const GdkRGBA *color,
+ float dx,
+ float dy,
+ float spread,
+ float blur_radius)
+{
+ GskVulkanBoxShadowInstance *instance = (GskVulkanBoxShadowInstance *) data;
+
+ gsk_rounded_rect_to_float (outline, instance->outline);
+ instance->color[0] = color->red;
+ instance->color[1] = color->green;
+ instance->color[2] = color->blue;
+ instance->color[3] = color->alpha;
+ instance->offset[0] = dx;
+ instance->offset[1] = dy;
+ instance->spread = spread;
+ instance->blur_radius = blur_radius;
+}
+
+gsize
+gsk_vulkan_box_shadow_pipeline_draw (GskVulkanBoxShadowPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6 * 8, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskroundedrect.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBoxShadowPipelineLayout GskVulkanBoxShadowPipelineLayout;
+
+#define GSK_TYPE_VULKAN_BOX_SHADOW_PIPELINE (gsk_vulkan_box_shadow_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanBoxShadowPipeline, gsk_vulkan_box_shadow_pipeline, GSK, VULKAN_BOX_SHADOW_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_box_shadow_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline *pipeline);
+void gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *pipeline,
+ guchar *data,
+ const GskRoundedRect *outline,
+ const GdkRGBA *color,
+ float dx,
+ float dy,
+ float spread,
+ float blur_radius);
+
+gsize gsk_vulkan_box_shadow_pipeline_draw (GskVulkanBoxShadowPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BOX_SHADOW_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkanmemoryprivate.h"
+#include "gskvulkanpipelineprivate.h"
+
+struct _GskVulkanBuffer
+{
+ GdkVulkanContext *vulkan;
+
+ gsize size;
+
+ VkBuffer vk_buffer;
+
+ GskVulkanMemory *memory;
+};
+
+static GskVulkanBuffer *
+gsk_vulkan_buffer_new_internal (GdkVulkanContext *context,
+ gsize size,
+ VkBufferUsageFlags usage)
+{
+ VkMemoryRequirements requirements;
+ GskVulkanBuffer *self;
+
+ self = g_slice_new0 (GskVulkanBuffer);
+
+ self->vulkan = g_object_ref (context);
+ self->size = size;
+
+ GSK_VK_CHECK (vkCreateBuffer, gdk_vulkan_context_get_device (context),
+ &(VkBufferCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .size = size,
+ .flags = 0,
+ .usage = usage,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE
+ },
+ NULL,
+ &self->vk_buffer);
+
+ vkGetBufferMemoryRequirements (gdk_vulkan_context_get_device (context),
+ self->vk_buffer,
+ &requirements);
+
+ self->memory = gsk_vulkan_memory_new (context,
+ requirements.memoryTypeBits,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ size);
+
+ GSK_VK_CHECK (vkBindBufferMemory, gdk_vulkan_context_get_device (context),
+ self->vk_buffer,
+ gsk_vulkan_memory_get_device_memory (self->memory),
+ 0);
+ return self;
+}
+
+GskVulkanBuffer *
+gsk_vulkan_buffer_new (GdkVulkanContext *context,
+ gsize size)
+{
+ return gsk_vulkan_buffer_new_internal (context, size,
+ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
+ | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+}
+
+GskVulkanBuffer *
+gsk_vulkan_buffer_new_staging (GdkVulkanContext *context,
+ gsize size)
+{
+ return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
+}
+
+GskVulkanBuffer *
+gsk_vulkan_buffer_new_download (GdkVulkanContext *context,
+ gsize size)
+{
+ return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+}
+void
+gsk_vulkan_buffer_free (GskVulkanBuffer *self)
+{
+ vkDestroyBuffer (gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_buffer,
+ NULL);
+
+ gsk_vulkan_memory_free (self->memory);
+
+ g_object_unref (self->vulkan);
+
+ g_slice_free (GskVulkanBuffer, self);
+}
+
+VkBuffer
+gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self)
+{
+ return self->vk_buffer;
+}
+
+guchar *
+gsk_vulkan_buffer_map (GskVulkanBuffer *self)
+{
+ return gsk_vulkan_memory_map (self->memory);
+}
+
+void
+gsk_vulkan_buffer_unmap (GskVulkanBuffer *self)
+{
+ gsk_vulkan_memory_unmap (self->memory);
+}
--- /dev/null
+#ifndef __GSK_VULKAN_BUFFER_PRIVATE_H__
+#define __GSK_VULKAN_BUFFER_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBuffer GskVulkanBuffer;
+
+GskVulkanBuffer * gsk_vulkan_buffer_new (GdkVulkanContext *context,
+ gsize size);
+GskVulkanBuffer * gsk_vulkan_buffer_new_staging (GdkVulkanContext *context,
+ gsize size);
+GskVulkanBuffer * gsk_vulkan_buffer_new_download (GdkVulkanContext *context,
+ gsize size);
+void gsk_vulkan_buffer_free (GskVulkanBuffer *buffer);
+
+VkBuffer gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self);
+
+guchar * gsk_vulkan_buffer_map (GskVulkanBuffer *self);
+void gsk_vulkan_buffer_unmap (GskVulkanBuffer *self);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BUFFER_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanclipprivate.h"
+
+#include "gskroundedrectprivate.h"
+
+void
+gsk_vulkan_clip_init_empty (GskVulkanClip *clip,
+ const graphene_rect_t *rect)
+{
+ clip->type = GSK_VULKAN_CLIP_NONE;
+ gsk_rounded_rect_init_from_rect (&clip->rect, rect, 0);
+}
+
+static void
+gsk_vulkan_clip_init_copy (GskVulkanClip *self,
+ const GskVulkanClip *src)
+{
+ self->type = src->type;
+ gsk_rounded_rect_init_copy (&self->rect, &src->rect);
+}
+
+gboolean
+gsk_vulkan_clip_intersect_rect (GskVulkanClip *dest,
+ const GskVulkanClip *src,
+ const graphene_rect_t *rect)
+{
+ if (graphene_rect_contains_rect (rect, &src->rect.bounds))
+ {
+ gsk_vulkan_clip_init_copy (dest, src);
+ return TRUE;
+ }
+ if (!graphene_rect_intersection (rect, &src->rect.bounds, NULL))
+ {
+ dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+ return TRUE;
+ }
+
+ switch (src->type)
+ {
+ case GSK_VULKAN_CLIP_ALL_CLIPPED:
+ dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+ break;
+
+ case GSK_VULKAN_CLIP_NONE:
+ gsk_vulkan_clip_init_copy (dest, src);
+ if (graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
+ dest->type = GSK_VULKAN_CLIP_RECT;
+ else
+ dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+ break;
+
+ case GSK_VULKAN_CLIP_RECT:
+ gsk_vulkan_clip_init_copy (dest, src);
+ if (!graphene_rect_intersection (&dest->rect.bounds, rect, &dest->rect.bounds))
+ dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+ break;
+
+ case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+ case GSK_VULKAN_CLIP_ROUNDED:
+ if (gsk_rounded_rect_contains_rect (&src->rect, rect))
+ {
+ dest->type = GSK_VULKAN_CLIP_RECT;
+ gsk_rounded_rect_init_from_rect (&dest->rect, rect, 0);
+ }
+ else
+ {
+ /* some points of rect are inside src's rounded rect,
+ * some are outside. */
+ /* XXX: If the 2 rects don't intersect on rounded corners,
+ * we could actually compute a new clip here.
+ */
+ return FALSE;
+ }
+
+ default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
+ const GskVulkanClip *src,
+ const GskRoundedRect *rounded)
+{
+ if (gsk_rounded_rect_contains_rect (rounded, &src->rect.bounds))
+ {
+ gsk_vulkan_clip_init_copy (dest, src);
+ return TRUE;
+ }
+ if (!graphene_rect_intersection (&rounded->bounds, &src->rect.bounds, NULL))
+ {
+ dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+ return TRUE;
+ }
+
+ switch (src->type)
+ {
+ case GSK_VULKAN_CLIP_ALL_CLIPPED:
+ dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
+ break;
+
+ case GSK_VULKAN_CLIP_NONE:
+ dest->type = gsk_rounded_rect_is_circular (&dest->rect) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
+ gsk_rounded_rect_init_copy (&dest->rect, rounded);
+ break;
+
+ case GSK_VULKAN_CLIP_RECT:
+ if (graphene_rect_contains_rect (&src->rect.bounds, &rounded->bounds))
+ {
+ dest->type = gsk_rounded_rect_is_circular (&dest->rect) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
+ gsk_rounded_rect_init_copy (&dest->rect, rounded);
+ return TRUE;
+ }
+ /* some points of rect are inside src's rounded rect,
+ * some are outside. */
+ /* XXX: If the 2 rects don't intersect on rounded corners,
+ * we could actually compute a new clip here.
+ */
+ return FALSE;
+
+ case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+ case GSK_VULKAN_CLIP_ROUNDED:
+ /* XXX: improve */
+ return FALSE;
+
+ default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gsk_vulkan_clip_transform (GskVulkanClip *dest,
+ const GskVulkanClip *src,
+ const graphene_matrix_t *transform,
+ const graphene_rect_t *viewport)
+{
+ switch (src->type)
+ {
+ default:
+ g_assert_not_reached();
+ return FALSE;
+
+ case GSK_VULKAN_CLIP_ALL_CLIPPED:
+ gsk_vulkan_clip_init_copy (dest, src);
+ return TRUE;
+
+ case GSK_VULKAN_CLIP_NONE:
+ gsk_vulkan_clip_init_empty (dest, viewport);
+ return TRUE;
+
+ case GSK_VULKAN_CLIP_RECT:
+ case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+ case GSK_VULKAN_CLIP_ROUNDED:
+ /* FIXME: Handle 2D operations, in particular transform and scale */
+ return FALSE;
+ }
+}
+
+gboolean
+gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
+ const graphene_rect_t *rect)
+{
+ switch (self->type)
+ {
+ default:
+ g_assert_not_reached();
+ case GSK_VULKAN_CLIP_ALL_CLIPPED:
+ return FALSE;
+
+ case GSK_VULKAN_CLIP_NONE:
+ return TRUE;
+
+ case GSK_VULKAN_CLIP_RECT:
+ return graphene_rect_contains_rect (&self->rect.bounds, rect);
+
+ case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+ case GSK_VULKAN_CLIP_ROUNDED:
+ return gsk_rounded_rect_contains_rect (&self->rect, rect);
+ }
+}
--- /dev/null
+#ifndef __GSK_VULKAN_CLIP_PRIVATE_H__
+#define __GSK_VULKAN_CLIP_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <graphene.h>
+#include <gsk/gskroundedrect.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ /* The whole area is clipped, no drawing is necessary.
+ * This can't be handled by return values because for return
+ * values we return if clips could even be computed.
+ */
+ GSK_VULKAN_CLIP_ALL_CLIPPED,
+ /* No clipping is necessary, but the clip rect is set
+ * to the actual bounds of the underlying framebuffer
+ */
+ GSK_VULKAN_CLIP_NONE,
+ /* The clip is a rectangular area */
+ GSK_VULKAN_CLIP_RECT,
+ /* The clip is a rounded rectangle, and for every corner
+ * corner.width == corner.height is true
+ */
+ GSK_VULKAN_CLIP_ROUNDED_CIRCULAR,
+ /* The clip is a rounded rectangle */
+ GSK_VULKAN_CLIP_ROUNDED
+} GskVulkanClipComplexity;
+
+typedef struct _GskVulkanClip GskVulkanClip;
+
+struct _GskVulkanClip
+{
+ GskVulkanClipComplexity type;
+ GskRoundedRect rect;
+};
+
+void gsk_vulkan_clip_init_empty (GskVulkanClip *clip,
+ const graphene_rect_t *rect);
+
+gboolean gsk_vulkan_clip_intersect_rect (GskVulkanClip *dest,
+ const GskVulkanClip *src,
+ const graphene_rect_t *rect) G_GNUC_WARN_UNUSED_RESULT;
+gboolean gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
+ const GskVulkanClip *src,
+ const GskRoundedRect *rounded) G_GNUC_WARN_UNUSED_RESULT;
+gboolean gsk_vulkan_clip_transform (GskVulkanClip *dest,
+ const GskVulkanClip *src,
+ const graphene_matrix_t*transform,
+ const graphene_rect_t *viewport) G_GNUC_WARN_UNUSED_RESULT;
+
+gboolean gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
+ const graphene_rect_t *rect) G_GNUC_WARN_UNUSED_RESULT;
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_CLIP_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkancolorpipelineprivate.h"
+
+struct _GskVulkanColorPipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanColorInstance GskVulkanColorInstance;
+
+struct _GskVulkanColorInstance
+{
+ float rect[4];
+ float color[4];
+};
+
+G_DEFINE_TYPE (GskVulkanColorPipeline, gsk_vulkan_color_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_color_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanColorInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = 0,
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanColorInstance, color),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_color_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanColorPipeline *self = GSK_VULKAN_COLOR_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_color_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_color_pipeline_class_init (GskVulkanColorPipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_color_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_color_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_color_pipeline_init (GskVulkanColorPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_color_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_COLOR_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_color_pipeline_count_vertex_data (GskVulkanColorPipeline *pipeline)
+{
+ return sizeof (GskVulkanColorInstance);
+}
+
+void
+gsk_vulkan_color_pipeline_collect_vertex_data (GskVulkanColorPipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const GdkRGBA *color)
+{
+ GskVulkanColorInstance *instance = (GskVulkanColorInstance *) data;
+
+ instance->rect[0] = rect->origin.x;
+ instance->rect[1] = rect->origin.y;
+ instance->rect[2] = rect->size.width;
+ instance->rect[3] = rect->size.height;
+ instance->color[0] = color->red;
+ instance->color[1] = color->green;
+ instance->color[2] = color->blue;
+ instance->color[3] = color->alpha;
+}
+
+gsize
+gsk_vulkan_color_pipeline_draw (GskVulkanColorPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanColorPipelineLayout GskVulkanColorPipelineLayout;
+
+#define GSK_TYPE_VULKAN_COLOR_PIPELINE (gsk_vulkan_color_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanColorPipeline, gsk_vulkan_color_pipeline, GSK, VULKAN_COLOR_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_color_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_color_pipeline_count_vertex_data (GskVulkanColorPipeline *pipeline);
+void gsk_vulkan_color_pipeline_collect_vertex_data (GskVulkanColorPipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const GdkRGBA *color);
+gsize gsk_vulkan_color_pipeline_draw (GskVulkanColorPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_COLOR_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkancolortextpipelineprivate.h"
+
+struct _GskVulkanColorTextPipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanColorTextInstance GskVulkanColorTextInstance;
+
+struct _GskVulkanColorTextInstance
+{
+ float rect[4];
+ float tex_rect[4];
+};
+
+G_DEFINE_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_color_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanColorTextInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, rect),
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, tex_rect),
+ },
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_color_text_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanColorTextPipeline *self = GSK_VULKAN_COLOR_TEXT_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_color_text_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_color_text_pipeline_class_init (GskVulkanColorTextPipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_color_text_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_color_text_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_color_text_pipeline_init (GskVulkanColorTextPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_color_text_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE, context, layout, shader_name, render_pass,
+ VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
+}
+
+gsize
+gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
+ int num_instances)
+{
+ return sizeof (GskVulkanColorTextInstance) * num_instances;
+}
+
+void
+gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
+ guchar *data,
+ GskVulkanRenderer *renderer,
+ const graphene_rect_t *rect,
+ PangoFont *font,
+ guint total_glyphs,
+ const PangoGlyphInfo *glyphs,
+ float x,
+ float y,
+ guint start_glyph,
+ guint num_glyphs,
+ float scale)
+{
+ GskVulkanColorTextInstance *instances = (GskVulkanColorTextInstance *) data;
+ int i;
+ int count = 0;
+ int x_position = 0;
+
+ for (i = 0; i < start_glyph; i++)
+ x_position += glyphs[i].geometry.width;
+
+ for (; i < total_glyphs && count < num_glyphs; i++)
+ {
+ const PangoGlyphInfo *gi = &glyphs[i];
+
+ if (gi->glyph != PANGO_GLYPH_EMPTY)
+ {
+ double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
+ double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
+ GskVulkanColorTextInstance *instance = &instances[count];
+ GskVulkanCachedGlyph *glyph;
+
+ glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
+
+ instance->tex_rect[0] = glyph->tx;
+ instance->tex_rect[1] = glyph->ty;
+ instance->tex_rect[2] = glyph->tw;
+ instance->tex_rect[3] = glyph->th;
+
+ instance->rect[0] = x + cx + glyph->draw_x;
+ instance->rect[1] = y + cy + glyph->draw_y;
+ instance->rect[2] = glyph->draw_width;
+ instance->rect[3] = glyph->draw_height;
+
+ count++;
+ }
+ x_position += gi->geometry.width;
+ }
+}
+
+gsize
+gsk_vulkan_color_text_pipeline_draw (GskVulkanColorTextPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrendererprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanColorTextPipelineLayout GskVulkanColorTextPipelineLayout;
+
+#define GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE (gsk_vulkan_color_text_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK, VULKAN_COLOR_TEXT_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_color_text_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
+ int num_instances);
+void gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
+ guchar *data,
+ GskVulkanRenderer *renderer,
+ const graphene_rect_t *rect,
+ PangoFont *font,
+ guint total_glyphs,
+ const PangoGlyphInfo *glyphs,
+ float x,
+ float y,
+ guint start_glyph,
+ guint num_glyphs,
+ float scale);
+gsize gsk_vulkan_color_text_pipeline_draw (GskVulkanColorTextPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_COLOR_TEXT_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkancommandpoolprivate.h"
+#include "gskvulkanpipelineprivate.h"
+
+struct _GskVulkanCommandPool
+{
+ GdkVulkanContext *vulkan;
+
+ VkCommandPool vk_command_pool;
+};
+
+GskVulkanCommandPool *
+gsk_vulkan_command_pool_new (GdkVulkanContext *context)
+{
+ GskVulkanCommandPool *self;
+
+ self = g_slice_new0 (GskVulkanCommandPool);
+
+ self->vulkan = g_object_ref (context);
+
+ GSK_VK_CHECK (vkCreateCommandPool, gdk_vulkan_context_get_device (context),
+ &(const VkCommandPoolCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ .queueFamilyIndex = gdk_vulkan_context_get_queue_family_index (self->vulkan),
+ .flags = 0
+ },
+ NULL,
+ &self->vk_command_pool);
+
+ return self;
+}
+
+void
+gsk_vulkan_command_pool_free (GskVulkanCommandPool *self)
+{
+ vkDestroyCommandPool (gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_command_pool,
+ NULL);
+
+ g_slice_free (GskVulkanCommandPool, self);
+}
+
+void
+gsk_vulkan_command_pool_reset (GskVulkanCommandPool *self)
+{
+ GSK_VK_CHECK (vkResetCommandPool, gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_command_pool,
+ 0);
+}
+
+VkCommandBuffer
+gsk_vulkan_command_pool_get_buffer (GskVulkanCommandPool *self)
+{
+ VkCommandBuffer command_buffer;
+
+ GSK_VK_CHECK (vkAllocateCommandBuffers, gdk_vulkan_context_get_device (self->vulkan),
+ &(VkCommandBufferAllocateInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .commandPool = self->vk_command_pool,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .commandBufferCount = 1,
+ },
+ &command_buffer);
+
+ GSK_VK_CHECK (vkBeginCommandBuffer, command_buffer,
+ &(VkCommandBufferBeginInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = 0
+ });
+
+ return command_buffer;
+}
+
+void
+gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
+ VkCommandBuffer command_buffer,
+ gsize wait_semaphore_count,
+ VkSemaphore *wait_semaphores,
+ gsize signal_semaphore_count,
+ VkSemaphore *signal_semaphores,
+ VkFence fence)
+{
+ VkPipelineStageFlags *wait_semaphore_flags = NULL;
+
+ GSK_VK_CHECK (vkEndCommandBuffer, command_buffer);
+
+ if (wait_semaphore_count > 0)
+ {
+ wait_semaphore_flags = alloca (sizeof (VkPipelineStageFlags) * wait_semaphore_count);
+ for (int i = 0; i < wait_semaphore_count; i++)
+ wait_semaphore_flags[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ }
+
+ GSK_VK_CHECK (vkQueueSubmit, gdk_vulkan_context_get_queue (self->vulkan),
+ 1,
+ &(VkSubmitInfo) {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ .waitSemaphoreCount = wait_semaphore_count,
+ .pWaitSemaphores = wait_semaphores,
+ .pWaitDstStageMask = wait_semaphore_flags,
+ .commandBufferCount = 1,
+ .pCommandBuffers = (VkCommandBuffer[1]) {
+ command_buffer
+ },
+ .signalSemaphoreCount = signal_semaphore_count,
+ .pSignalSemaphores = signal_semaphores,
+ },
+ fence);
+}
+
--- /dev/null
+#ifndef __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__
+#define __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanCommandPool GskVulkanCommandPool;
+
+GskVulkanCommandPool * gsk_vulkan_command_pool_new (GdkVulkanContext *context);
+void gsk_vulkan_command_pool_free (GskVulkanCommandPool *self);
+
+void gsk_vulkan_command_pool_reset (GskVulkanCommandPool *self);
+
+VkCommandBuffer gsk_vulkan_command_pool_get_buffer (GskVulkanCommandPool *self);
+void gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
+ VkCommandBuffer buffer,
+ gsize wait_semaphore_count,
+ VkSemaphore *wait_semaphores,
+ gsize signal_semaphores_count,
+ VkSemaphore *signal_semaphores,
+ VkFence fence);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_COMMAND_POOL_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkancrossfadepipelineprivate.h"
+
+struct _GskVulkanCrossFadePipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanCrossFadeInstance GskVulkanCrossFadeInstance;
+
+struct _GskVulkanCrossFadeInstance
+{
+ float rect[4];
+ float start_tex_rect[4];
+ float end_tex_rect[4];
+ float progress;
+};
+
+G_DEFINE_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_cross_fade_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanCrossFadeInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = 0,
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_rect),
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_rect),
+ },
+ {
+ .location = 3,
+ .binding = 0,
+ .format = VK_FORMAT_R32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, progress),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_cross_fade_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanCrossFadePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_cross_fade_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_cross_fade_pipeline_class_init (GskVulkanCrossFadePipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_cross_fade_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_cross_fade_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_cross_fade_pipeline_init (GskVulkanCrossFadePipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline)
+{
+ return sizeof (GskVulkanCrossFadeInstance);
+}
+
+void
+gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *bounds,
+ const graphene_rect_t *start_tex_rect,
+ const graphene_rect_t *end_tex_rect,
+ double progress)
+{
+ GskVulkanCrossFadeInstance *instance = (GskVulkanCrossFadeInstance *) data;
+
+ instance->rect[0] = bounds->origin.x;
+ instance->rect[1] = bounds->origin.y;
+ instance->rect[2] = bounds->size.width;
+ instance->rect[3] = bounds->size.height;
+
+ instance->start_tex_rect[0] = start_tex_rect->origin.x;
+ instance->start_tex_rect[1] = start_tex_rect->origin.y;
+ instance->start_tex_rect[2] = start_tex_rect->size.width;
+ instance->start_tex_rect[3] = start_tex_rect->size.height;
+
+ instance->end_tex_rect[0] = end_tex_rect->origin.x;
+ instance->end_tex_rect[1] = end_tex_rect->origin.y;
+ instance->end_tex_rect[2] = end_tex_rect->size.width;
+ instance->end_tex_rect[3] = end_tex_rect->size.height;
+
+ instance->progress = progress;
+}
+
+gsize
+gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanCrossFadePipelineLayout GskVulkanCrossFadePipelineLayout;
+
+#define GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE (gsk_vulkan_cross_fade_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK, VULKAN_CROSS_FADE_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline);
+void gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *bounds,
+ const graphene_rect_t *start_bounds,
+ const graphene_rect_t *end_bounds,
+ double progress);
+gsize gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkaneffectpipelineprivate.h"
+
+struct _GskVulkanEffectPipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanEffectInstance GskVulkanEffectInstance;
+
+struct _GskVulkanEffectInstance
+{
+ float rect[4];
+ float tex_rect[4];
+ float color_matrix[16];
+ float color_offset[4];
+};
+
+G_DEFINE_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_effect_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanEffectInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = 0,
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, tex_rect),
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix),
+ },
+ {
+ .location = 3,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 4,
+ },
+ {
+ .location = 4,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 8,
+ },
+ {
+ .location = 5,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 12,
+ },
+ {
+ .location = 6,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_offset),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_effect_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanEffectPipeline *self = GSK_VULKAN_EFFECT_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_effect_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_effect_pipeline_class_init (GskVulkanEffectPipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_effect_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_effect_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_effect_pipeline_init (GskVulkanEffectPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_effect_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_EFFECT_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline)
+{
+ return sizeof (GskVulkanEffectInstance);
+}
+
+void
+gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const graphene_rect_t *tex_rect,
+ const graphene_matrix_t *color_matrix,
+ const graphene_vec4_t *color_offset)
+{
+ GskVulkanEffectInstance *instance = (GskVulkanEffectInstance *) data;
+
+ instance->rect[0] = rect->origin.x;
+ instance->rect[1] = rect->origin.y;
+ instance->rect[2] = rect->size.width;
+ instance->rect[3] = rect->size.height;
+ instance->tex_rect[0] = tex_rect->origin.x;
+ instance->tex_rect[1] = tex_rect->origin.y;
+ instance->tex_rect[2] = tex_rect->size.width;
+ instance->tex_rect[3] = tex_rect->size.height;
+ graphene_matrix_to_float (color_matrix, instance->color_matrix);
+ graphene_vec4_to_float (color_offset, instance->color_offset);
+}
+
+gsize
+gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanEffectPipelineLayout GskVulkanEffectPipelineLayout;
+
+#define GSK_TYPE_VULKAN_EFFECT_PIPELINE (gsk_vulkan_effect_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK, VULKAN_EFFECT_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_effect_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline);
+void gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const graphene_rect_t *tex_rect,
+ const graphene_matrix_t *color_matrix,
+ const graphene_vec4_t *color_offset);
+gsize gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanglyphcacheprivate.h"
+
+#include "gskvulkanimageprivate.h"
+#include "gskdebugprivate.h"
+#include "gskprivate.h"
+
+#include <graphene.h>
+
+/* Parameters for our cache eviction strategy.
+ *
+ * Each cached glyph has an age that gets reset every time a cached glyph gets used.
+ * Glyphs that have not been used for the MAX_AGE frames are considered old. We keep
+ * count of the pixels of each atlas that are taken up by old glyphs. We check the
+ * fraction of old pixels every CHECK_INTERVAL frames, and if it is above MAX_OLD, then
+ * we drop the atlas an all the glyphs contained in it from the cache.
+ */
+
+#define MAX_AGE 60
+#define CHECK_INTERVAL 10
+#define MAX_OLD 0.333
+
+
+typedef struct {
+ GskVulkanImage *image;
+ int width, height;
+ int x, y, y0;
+ int num_glyphs;
+ GList *dirty_glyphs;
+ guint old_pixels;
+} Atlas;
+
+struct _GskVulkanGlyphCache {
+ GObject parent_instance;
+
+ GdkVulkanContext *vulkan;
+
+ GHashTable *hash_table;
+ GPtrArray *atlases;
+
+ guint64 timestamp;
+};
+
+struct _GskVulkanGlyphCacheClass {
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GskVulkanGlyphCache, gsk_vulkan_glyph_cache, G_TYPE_OBJECT)
+
+static guint glyph_cache_hash (gconstpointer v);
+static gboolean glyph_cache_equal (gconstpointer v1,
+ gconstpointer v2);
+static void glyph_cache_key_free (gpointer v);
+static void glyph_cache_value_free (gpointer v);
+static void dirty_glyph_free (gpointer v);
+
+static Atlas *
+create_atlas (GskVulkanGlyphCache *cache)
+{
+ Atlas *atlas;
+
+ atlas = g_new0 (Atlas, 1);
+ atlas->width = 512;
+ atlas->height = 512;
+ atlas->y0 = 1;
+ atlas->y = 1;
+ atlas->x = 1;
+ atlas->image = NULL;
+ atlas->num_glyphs = 0;
+ atlas->dirty_glyphs = NULL;
+
+ return atlas;
+}
+
+static void
+free_atlas (gpointer v)
+{
+ Atlas *atlas = v;
+
+ g_clear_object (&atlas->image);
+ g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
+ g_free (atlas);
+}
+
+static void
+gsk_vulkan_glyph_cache_init (GskVulkanGlyphCache *cache)
+{
+ cache->hash_table = g_hash_table_new_full (glyph_cache_hash, glyph_cache_equal,
+ glyph_cache_key_free, glyph_cache_value_free);
+ cache->atlases = g_ptr_array_new_with_free_func (free_atlas);
+}
+
+static void
+gsk_vulkan_glyph_cache_finalize (GObject *object)
+{
+ GskVulkanGlyphCache *cache = GSK_VULKAN_GLYPH_CACHE (object);
+
+ g_ptr_array_unref (cache->atlases);
+ g_hash_table_unref (cache->hash_table);
+
+ G_OBJECT_CLASS (gsk_vulkan_glyph_cache_parent_class)->finalize (object);
+}
+
+static void
+gsk_vulkan_glyph_cache_class_init (GskVulkanGlyphCacheClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gsk_vulkan_glyph_cache_finalize;
+}
+
+typedef struct {
+ PangoFont *font;
+ PangoGlyph glyph;
+ guint scale; /* times 1024 */
+} GlyphCacheKey;
+
+static gboolean
+glyph_cache_equal (gconstpointer v1, gconstpointer v2)
+{
+ const GlyphCacheKey *key1 = v1;
+ const GlyphCacheKey *key2 = v2;
+
+ return key1->font == key2->font &&
+ key1->glyph == key2->glyph &&
+ key1->scale == key2->scale;
+}
+
+static guint
+glyph_cache_hash (gconstpointer v)
+{
+ const GlyphCacheKey *key = v;
+
+ return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ key->scale;
+}
+
+static void
+glyph_cache_key_free (gpointer v)
+{
+ GlyphCacheKey *f = v;
+
+ g_object_unref (f->font);
+ g_free (f);
+}
+
+static void
+glyph_cache_value_free (gpointer v)
+{
+ g_free (v);
+}
+
+typedef struct {
+ GlyphCacheKey *key;
+ GskVulkanCachedGlyph *value;
+ cairo_surface_t *surface;
+} DirtyGlyph;
+
+static void
+dirty_glyph_free (gpointer v)
+{
+ DirtyGlyph *glyph = v;
+
+ if (glyph->surface)
+ cairo_surface_destroy (glyph->surface);
+ g_free (glyph);
+}
+
+static void
+add_to_cache (GskVulkanGlyphCache *cache,
+ GlyphCacheKey *key,
+ GskVulkanCachedGlyph *value)
+{
+ Atlas *atlas;
+ int i;
+ DirtyGlyph *dirty;
+ int width = value->draw_width * key->scale / 1024;
+ int height = value->draw_height * key->scale / 1024;
+
+ for (i = 0; i < cache->atlases->len; i++)
+ {
+ int x, y, y0;
+
+ atlas = g_ptr_array_index (cache->atlases, i);
+ x = atlas->x;
+ y = atlas->y;
+ y0 = atlas->y0;
+
+ if (atlas->x + width + 1 >= atlas->width)
+ {
+ /* start a new row */
+ y0 = y + 1;
+ x = 1;
+ }
+
+ if (y0 + height + 1 >= atlas->height)
+ continue;
+
+ atlas->y0 = y0;
+ atlas->x = x;
+ atlas->y = y;
+ break;
+ }
+
+ if (i == cache->atlases->len)
+ {
+ atlas = create_atlas (cache);
+ g_ptr_array_add (cache->atlases, atlas);
+ }
+
+ value->tx = (float)atlas->x / atlas->width;
+ value->ty = (float)atlas->y0 / atlas->height;
+ value->tw = (float)width / atlas->width;
+ value->th = (float)height / atlas->height;
+
+ value->texture_index = i;
+
+ dirty = g_new (DirtyGlyph, 1);
+ dirty->key = key;
+ dirty->value = value;
+ atlas->dirty_glyphs = g_list_prepend (atlas->dirty_glyphs, dirty);
+
+ atlas->x = atlas->x + width + 1;
+ atlas->y = MAX (atlas->y, atlas->y0 + height + 1);
+
+ atlas->num_glyphs++;
+
+#ifdef G_ENABLE_DEBUG
+ if (GSK_DEBUG_CHECK(GLYPH_CACHE))
+ {
+ g_print ("Glyph cache:\n");
+ for (i = 0; i < cache->atlases->len; i++)
+ {
+ atlas = g_ptr_array_index (cache->atlases, i);
+ g_print ("\tAtlas %d (%dx%d): %d glyphs (%d dirty), %.2g%% old pixels, filled to %d, %d / %d\n",
+ i, atlas->width, atlas->height,
+ atlas->num_glyphs, g_list_length (atlas->dirty_glyphs),
+ 100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height),
+ atlas->x, atlas->y0, atlas->y);
+ }
+ }
+#endif
+}
+
+static void
+render_glyph (Atlas *atlas,
+ DirtyGlyph *glyph,
+ GskImageRegion *region)
+{
+ GlyphCacheKey *key = glyph->key;
+ GskVulkanCachedGlyph *value = glyph->value;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ PangoGlyphString glyphs;
+ PangoGlyphInfo gi;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ value->draw_width * key->scale / 1024,
+ value->draw_height * key->scale / 1024);
+ cairo_surface_set_device_scale (surface, key->scale / 1024.0, key->scale / 1024.0);
+
+ cr = cairo_create (surface);
+ cairo_set_source_rgba (cr, 1, 1, 1, 1);
+
+ gi.glyph = key->glyph;
+ gi.geometry.width = value->draw_width * 1024;
+ if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
+ gi.geometry.x_offset = 0;
+ else
+ gi.geometry.x_offset = - value->draw_x * 1024;
+ gi.geometry.y_offset = - value->draw_y * 1024;
+
+ glyphs.num_glyphs = 1;
+ glyphs.glyphs = &gi;
+
+ pango_cairo_show_glyph_string (cr, key->font, &glyphs);
+
+ cairo_destroy (cr);
+
+ glyph->surface = surface;
+
+ region->data = cairo_image_surface_get_data (surface);
+ region->width = cairo_image_surface_get_width (surface);
+ region->height = cairo_image_surface_get_height (surface);
+ region->stride = cairo_image_surface_get_stride (surface);
+ region->x = (gsize)(value->tx * atlas->width);
+ region->y = (gsize)(value->ty * atlas->height);
+}
+
+static void
+upload_dirty_glyphs (Atlas *atlas,
+ GskVulkanUploader *uploader)
+{
+ GList *l;
+ guint num_regions;
+ GskImageRegion *regions;
+ int i;
+
+ num_regions = g_list_length (atlas->dirty_glyphs);
+ regions = alloca (sizeof (GskImageRegion) * num_regions);
+
+ for (l = atlas->dirty_glyphs, i = 0; l; l = l->next, i++)
+ render_glyph (atlas, (DirtyGlyph *)l->data, ®ions[i]);
+
+ GSK_NOTE (GLYPH_CACHE,
+ g_print ("uploading %d glyphs to cache\n", num_regions));
+
+ gsk_vulkan_image_upload_regions (atlas->image, uploader, num_regions, regions);
+
+ g_list_free_full (atlas->dirty_glyphs, dirty_glyph_free);
+ atlas->dirty_glyphs = NULL;
+}
+
+GskVulkanGlyphCache *
+gsk_vulkan_glyph_cache_new (GdkVulkanContext *vulkan)
+{
+ GskVulkanGlyphCache *cache;
+
+ cache = GSK_VULKAN_GLYPH_CACHE (g_object_new (GSK_TYPE_VULKAN_GLYPH_CACHE, NULL));
+ cache->vulkan = vulkan;
+ g_ptr_array_add (cache->atlases, create_atlas (cache));
+
+ return cache;
+}
+
+GskVulkanCachedGlyph *
+gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
+ gboolean create,
+ PangoFont *font,
+ PangoGlyph glyph,
+ float scale)
+{
+ GlyphCacheKey lookup_key;
+ GskVulkanCachedGlyph *value;
+
+ lookup_key.font = font;
+ lookup_key.glyph = glyph;
+ lookup_key.scale = (guint)(scale * 1024);
+
+ value = g_hash_table_lookup (cache->hash_table, &lookup_key);
+
+ if (value)
+ {
+ if (cache->timestamp - value->timestamp >= MAX_AGE)
+ {
+ Atlas *atlas = g_ptr_array_index (cache->atlases, value->texture_index);
+
+ atlas->old_pixels -= value->draw_width * value->draw_height;
+ value->timestamp = cache->timestamp;
+ }
+ }
+
+ if (create && value == NULL)
+ {
+ GlyphCacheKey *key;
+ PangoRectangle ink_rect;
+
+ key = g_new (GlyphCacheKey, 1);
+ value = g_new0 (GskVulkanCachedGlyph, 1);
+
+ pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
+ pango_extents_to_pixels (&ink_rect, NULL);
+
+ value->draw_x = ink_rect.x;
+ value->draw_y = ink_rect.y;
+ value->draw_width = ink_rect.width;
+ value->draw_height = ink_rect.height;
+ value->timestamp = cache->timestamp;
+
+ key->font = g_object_ref (font);
+ key->glyph = glyph;
+ key->scale = (guint)(scale * 1024);
+
+ if (ink_rect.width > 0 && ink_rect.height > 0)
+ add_to_cache (cache, key, value);
+
+ g_hash_table_insert (cache->hash_table, key, value);
+ }
+
+ return value;
+}
+
+GskVulkanImage *
+gsk_vulkan_glyph_cache_get_glyph_image (GskVulkanGlyphCache *cache,
+ GskVulkanUploader *uploader,
+ guint index)
+{
+ Atlas *atlas;
+
+ g_return_val_if_fail (index < cache->atlases->len, NULL);
+
+ atlas = g_ptr_array_index (cache->atlases, index);
+
+ if (atlas->image == NULL)
+ atlas->image = gsk_vulkan_image_new_for_atlas (cache->vulkan, atlas->width, atlas->height);
+
+ if (atlas->dirty_glyphs)
+ upload_dirty_glyphs (atlas, uploader);
+
+ return atlas->image;
+}
+
+void
+gsk_vulkan_glyph_cache_begin_frame (GskVulkanGlyphCache *cache)
+{
+ int i, j;
+ guint *drops;
+ guint *shifts;
+ guint len;
+ GHashTableIter iter;
+ GlyphCacheKey *key;
+ GskVulkanCachedGlyph *value;
+ guint dropped = 0;
+
+ cache->timestamp++;
+
+ if (cache->timestamp % CHECK_INTERVAL != 0)
+ return;
+
+ len = cache->atlases->len;
+
+ /* look for glyphs that have grown old since last time */
+ g_hash_table_iter_init (&iter, cache->hash_table);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
+ {
+ guint age;
+
+ age = cache->timestamp - value->timestamp;
+ if (MAX_AGE <= age && age < MAX_AGE + CHECK_INTERVAL)
+ {
+ Atlas *atlas = g_ptr_array_index (cache->atlases, value->texture_index);
+ atlas->old_pixels += value->draw_width * value->draw_height;
+ }
+ }
+
+ drops = g_alloca (sizeof (guint) * len);
+ shifts = g_alloca (sizeof (guint) * len);
+
+ for (i = 0; i < len; i++)
+ {
+ drops[i] = 0;
+ shifts[i] = i;
+ }
+
+ /* look for atlases to drop, and create a mapping of updated texture indices */
+ for (i = cache->atlases->len - 1; i >= 0; i--)
+ {
+ Atlas *atlas = g_ptr_array_index (cache->atlases, i);
+
+ if (atlas->old_pixels > MAX_OLD * atlas->width * atlas->height)
+ {
+ GSK_NOTE(GLYPH_CACHE,
+ g_print ("Dropping atlas %d (%g.2%% old)\n", i, 100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height)));
+ g_ptr_array_remove_index (cache->atlases, i);
+
+ drops[i] = 1;
+ for (j = i; j + 1 < len; j++)
+ shifts[j + 1] = shifts[j];
+ }
+ }
+
+ /* no atlas dropped, we're done */
+ if (len == cache->atlases->len)
+ return;
+
+ /* purge glyphs and update texture indices */
+ g_hash_table_iter_init (&iter, cache->hash_table);
+
+ while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
+ {
+ if (drops[value->texture_index])
+ {
+ dropped++;
+ g_hash_table_iter_remove (&iter);
+ }
+ else
+ {
+ value->texture_index = shifts[value->texture_index];
+ }
+ }
+
+ GSK_NOTE(GLYPH_CACHE, g_print ("Dropped %d glyphs\n", dropped));
+}
--- /dev/null
+#ifndef __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__
+#define __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__
+
+#include <pango/pango.h>
+#include "gskvulkanrendererprivate.h"
+#include "gskvulkanimageprivate.h"
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_VULKAN_GLYPH_CACHE (gsk_vulkan_glyph_cache_get_type ())
+
+G_DECLARE_FINAL_TYPE(GskVulkanGlyphCache, gsk_vulkan_glyph_cache, GSK, VULKAN_GLYPH_CACHE, GObject)
+
+GskVulkanGlyphCache *gsk_vulkan_glyph_cache_new (GdkVulkanContext *vulkan);
+
+GskVulkanImage * gsk_vulkan_glyph_cache_get_glyph_image (GskVulkanGlyphCache *cache,
+ GskVulkanUploader *uploader,
+ guint index);
+
+GskVulkanCachedGlyph *gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
+ gboolean create,
+ PangoFont *font,
+ PangoGlyph glyph,
+ float scale);
+
+void gsk_vulkan_glyph_cache_begin_frame (GskVulkanGlyphCache *cache);
+
+#endif /* __GSK_VULKAN_GLYPH_CACHE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanimageprivate.h"
+
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkanmemoryprivate.h"
+#include "gskvulkanpipelineprivate.h"
+
+#include <string.h>
+
+struct _GskVulkanUploader
+{
+ GdkVulkanContext *vulkan;
+
+ GskVulkanCommandPool *command_pool;
+
+ GArray *before_buffer_barriers;
+ GArray *before_image_barriers;
+ VkCommandBuffer copy_buffer;
+ GArray *after_buffer_barriers;
+ GArray *after_image_barriers;
+
+ GSList *staging_image_free_list;
+ GSList *staging_buffer_free_list;
+};
+
+struct _GskVulkanImage
+{
+ GObject parent_instance;
+
+ GdkVulkanContext *vulkan;
+
+ gsize width;
+ gsize height;
+ VkImageUsageFlags vk_usage;
+ VkImage vk_image;
+ VkImageView vk_image_view;
+ VkImageLayout vk_image_layout;
+ VkAccessFlags vk_access;
+
+ GskVulkanMemory *memory;
+};
+
+G_DEFINE_TYPE (GskVulkanImage, gsk_vulkan_image, G_TYPE_OBJECT)
+
+GskVulkanUploader *
+gsk_vulkan_uploader_new (GdkVulkanContext *context,
+ GskVulkanCommandPool *command_pool)
+{
+ GskVulkanUploader *self;
+
+ self = g_slice_new0 (GskVulkanUploader);
+
+ self->vulkan = g_object_ref (context);
+ self->command_pool = command_pool;
+
+ self->before_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
+ self->after_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
+
+ self->before_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
+ self->after_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
+
+ return self;
+}
+
+void
+gsk_vulkan_uploader_free (GskVulkanUploader *self)
+{
+ gsk_vulkan_uploader_reset (self);
+
+ g_array_unref (self->after_buffer_barriers);
+ g_array_unref (self->before_buffer_barriers);
+ g_array_unref (self->after_image_barriers);
+ g_array_unref (self->before_image_barriers);
+
+ g_object_unref (self->vulkan);
+
+ g_slice_free (GskVulkanUploader, self);
+}
+
+static void
+gsk_vulkan_uploader_add_image_barrier (GskVulkanUploader *self,
+ gboolean after,
+ GskVulkanImage *image,
+ VkImageLayout new_layout,
+ VkAccessFlags new_access)
+{
+ GArray *array;
+ VkImageMemoryBarrier barrier = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .srcAccessMask = image->vk_access,
+ .dstAccessMask = new_access,
+ .oldLayout = image->vk_image_layout,
+ .newLayout = new_layout,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = image->vk_image,
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ }
+ };
+
+ if (after)
+ array = self->after_image_barriers;
+ else
+ array = self->before_image_barriers;
+
+ g_array_append_val (array, barrier);
+
+ image->vk_image_layout = new_layout;
+ image->vk_access = new_access;
+}
+
+static void
+gsk_vulkan_uploader_add_buffer_barrier (GskVulkanUploader *self,
+ gboolean after,
+ const VkBufferMemoryBarrier *barrier)
+{
+ GArray *array;
+
+ if (after)
+ array = self->after_buffer_barriers;
+ else
+ array = self->before_buffer_barriers;
+
+ g_array_append_val (array, *barrier);
+}
+
+static VkCommandBuffer
+gsk_vulkan_uploader_get_copy_buffer (GskVulkanUploader *self)
+{
+ if (self->copy_buffer == VK_NULL_HANDLE)
+ self->copy_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
+
+ return self->copy_buffer;
+}
+
+void
+gsk_vulkan_uploader_upload (GskVulkanUploader *self)
+{
+ if (self->before_buffer_barriers->len > 0 || self->before_image_barriers->len > 0)
+ {
+ VkCommandBuffer command_buffer;
+
+ command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
+ vkCmdPipelineBarrier (command_buffer,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0,
+ 0, NULL,
+ self->before_buffer_barriers->len, (VkBufferMemoryBarrier *) self->before_buffer_barriers->data,
+ self->before_image_barriers->len, (VkImageMemoryBarrier *) self->before_image_barriers->data);
+ gsk_vulkan_command_pool_submit_buffer (self->command_pool, command_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
+ g_array_set_size (self->before_buffer_barriers, 0);
+ g_array_set_size (self->before_image_barriers, 0);
+ }
+
+ /* append these to existing buffer */
+ if (self->after_buffer_barriers->len > 0 || self->after_image_barriers->len > 0)
+ {
+ VkCommandBuffer command_buffer = gsk_vulkan_uploader_get_copy_buffer (self);
+ vkCmdPipelineBarrier (command_buffer,
+ VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ 0,
+ 0, NULL,
+ self->after_buffer_barriers->len, (VkBufferMemoryBarrier *) self->after_buffer_barriers->data,
+ self->after_image_barriers->len, (VkImageMemoryBarrier *) self->after_image_barriers->data);
+ g_array_set_size (self->after_buffer_barriers, 0);
+ g_array_set_size (self->after_image_barriers, 0);
+ }
+
+ if (self->copy_buffer != VK_NULL_HANDLE)
+ {
+ gsk_vulkan_command_pool_submit_buffer (self->command_pool, self->copy_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
+ self->copy_buffer = VK_NULL_HANDLE;
+ }
+}
+
+void
+gsk_vulkan_uploader_reset (GskVulkanUploader *self)
+{
+ g_array_set_size (self->before_image_barriers, 0);
+ self->copy_buffer = VK_NULL_HANDLE;
+ g_array_set_size (self->after_image_barriers, 0);
+
+ g_slist_free_full (self->staging_image_free_list, g_object_unref);
+ self->staging_image_free_list = NULL;
+ g_slist_free_full (self->staging_buffer_free_list, (GDestroyNotify) gsk_vulkan_buffer_free);
+ self->staging_buffer_free_list = NULL;
+}
+
+static GskVulkanImage *
+gsk_vulkan_image_new (GdkVulkanContext *context,
+ gsize width,
+ gsize height,
+ VkImageTiling tiling,
+ VkImageUsageFlags usage,
+ VkImageLayout layout,
+ VkAccessFlags access,
+ VkMemoryPropertyFlags memory)
+{
+ VkMemoryRequirements requirements;
+ GskVulkanImage *self;
+
+ self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
+
+ self->vulkan = g_object_ref (context);
+ self->width = width;
+ self->height = height;
+ self->vk_usage = usage;
+ self->vk_image_layout = layout;
+ self->vk_access = access;
+
+ GSK_VK_CHECK (vkCreateImage, gdk_vulkan_context_get_device (context),
+ &(VkImageCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+ .flags = 0,
+ .imageType = VK_IMAGE_TYPE_2D,
+ .format = VK_FORMAT_B8G8R8A8_UNORM,
+ .extent = { width, height, 1 },
+ .mipLevels = 1,
+ .arrayLayers = 1,
+ .samples = VK_SAMPLE_COUNT_1_BIT,
+ .tiling = tiling,
+ .usage = usage,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ .initialLayout = self->vk_image_layout,
+ },
+ NULL,
+ &self->vk_image);
+
+ vkGetImageMemoryRequirements (gdk_vulkan_context_get_device (context),
+ self->vk_image,
+ &requirements);
+
+ self->memory = gsk_vulkan_memory_new (context,
+ requirements.memoryTypeBits,
+ memory,
+ requirements.size);
+
+ GSK_VK_CHECK (vkBindImageMemory, gdk_vulkan_context_get_device (context),
+ self->vk_image,
+ gsk_vulkan_memory_get_device_memory (self->memory),
+ 0);
+ return self;
+}
+
+static void
+gsk_vulkan_image_upload_data (GskVulkanImage *self,
+ guchar *data,
+ gsize width,
+ gsize height,
+ gsize data_stride)
+{
+ VkImageSubresource image_res;
+ VkSubresourceLayout image_layout;
+ gsize mem_stride;
+ guchar *mem;
+
+ image_res.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ image_res.mipLevel = 0;
+ image_res.arrayLayer = 0;
+
+ mem_stride = width * 4;
+ vkGetImageSubresourceLayout (gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_image, &image_res, &image_layout);
+
+ mem = gsk_vulkan_memory_map (self->memory) + image_layout.offset;
+
+ if (image_layout.rowPitch == width * 4 && data_stride == mem_stride)
+ {
+ memcpy (mem, data, data_stride * height);
+ }
+ else
+ {
+ for (gsize i = 0; i < height; i++)
+ {
+ memcpy (mem + i * image_layout.rowPitch, data + i * data_stride, width * 4);
+ }
+ }
+
+ gsk_vulkan_memory_unmap (self->memory);
+}
+
+static void
+gsk_vulkan_image_ensure_view (GskVulkanImage *self,
+ VkFormat format)
+{
+ if (self->vk_image_view == VK_NULL_HANDLE)
+ GSK_VK_CHECK (vkCreateImageView, gdk_vulkan_context_get_device (self->vulkan),
+ &(VkImageViewCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ .image = self->vk_image,
+ .viewType = VK_IMAGE_VIEW_TYPE_2D,
+ .format = format,
+ .components = {
+ .r = VK_COMPONENT_SWIZZLE_R,
+ .g = VK_COMPONENT_SWIZZLE_G,
+ .b = VK_COMPONENT_SWIZZLE_B,
+ .a = VK_COMPONENT_SWIZZLE_A,
+ },
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1,
+ },
+ },
+ NULL,
+ &self->vk_image_view);
+}
+
+static GskVulkanImage *
+gsk_vulkan_image_new_from_data_via_staging_buffer (GskVulkanUploader *uploader,
+ guchar *data,
+ gsize width,
+ gsize height,
+ gsize stride)
+{
+ GskVulkanImage *self;
+ GskVulkanBuffer *staging;
+ gsize buffer_size = width * height * 4;
+ guchar *mem;
+
+ staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, buffer_size);
+ mem = gsk_vulkan_buffer_map (staging);
+
+ if (stride == width * 4)
+ {
+ memcpy (mem, data, stride * height);
+ }
+ else
+ {
+ for (gsize i = 0; i < height; i++)
+ {
+ memcpy (mem + i * width * 4, data + i * stride, width * 4);
+ }
+ }
+
+ gsk_vulkan_buffer_unmap (staging);
+
+ gsk_vulkan_uploader_add_buffer_barrier (uploader,
+ FALSE,
+ &(VkBufferMemoryBarrier) {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+ .srcAccessMask = VK_ACCESS_HOST_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .buffer = gsk_vulkan_buffer_get_buffer(staging),
+ .offset = 0,
+ .size = buffer_size,
+ });
+
+ self = gsk_vulkan_image_new (uploader->vulkan,
+ width,
+ height,
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+ VK_IMAGE_USAGE_SAMPLED_BIT,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ gsk_vulkan_uploader_add_image_barrier (uploader,
+ FALSE,
+ self,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+
+ vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
+ gsk_vulkan_buffer_get_buffer (staging),
+ self->vk_image,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1,
+ (VkBufferImageCopy[1]) {
+ {
+ .bufferOffset = 0,
+ .imageSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ },
+ .imageOffset = { 0, 0, 0 },
+ .imageExtent = {
+ .width = width,
+ .height = height,
+ .depth = 1
+ }
+ }
+ });
+
+ gsk_vulkan_uploader_add_image_barrier (uploader,
+ TRUE,
+ self,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ VK_ACCESS_SHADER_READ_BIT);
+
+ uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, staging);
+
+ gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+ return self;
+}
+
+static GskVulkanImage *
+gsk_vulkan_image_new_from_data_via_staging_image (GskVulkanUploader *uploader,
+ guchar *data,
+ gsize width,
+ gsize height,
+ gsize stride)
+{
+ GskVulkanImage *self, *staging;
+
+ staging = gsk_vulkan_image_new (uploader->vulkan,
+ width,
+ height,
+ VK_IMAGE_TILING_LINEAR,
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
+ VK_IMAGE_LAYOUT_PREINITIALIZED,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+
+ gsk_vulkan_image_upload_data (staging, data, width, height, stride);
+
+ self = gsk_vulkan_image_new (uploader->vulkan,
+ width,
+ height,
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+ VK_IMAGE_USAGE_SAMPLED_BIT,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ gsk_vulkan_uploader_add_image_barrier (uploader,
+ FALSE,
+ staging,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ VK_ACCESS_TRANSFER_READ_BIT);
+
+ gsk_vulkan_uploader_add_image_barrier (uploader,
+ FALSE,
+ self,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+
+ vkCmdCopyImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
+ staging->vk_image,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ self->vk_image,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1,
+ &(VkImageCopy) {
+ .srcSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ },
+ .srcOffset = { 0, 0, 0 },
+ .dstSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ },
+ .dstOffset = { 0, 0, 0 },
+ .extent = {
+ .width = width,
+ .height = height,
+ .depth = 1
+ }
+ });
+
+ gsk_vulkan_uploader_add_image_barrier (uploader,
+ TRUE,
+ self,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ VK_ACCESS_SHADER_READ_BIT);
+
+ uploader->staging_image_free_list = g_slist_prepend (uploader->staging_image_free_list, staging);
+
+ gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+ return self;
+}
+
+static GskVulkanImage *
+gsk_vulkan_image_new_from_data_directly (GskVulkanUploader *uploader,
+ guchar *data,
+ gsize width,
+ gsize height,
+ gsize stride)
+{
+ GskVulkanImage *self;
+
+ self = gsk_vulkan_image_new (uploader->vulkan,
+ width,
+ height,
+ VK_IMAGE_TILING_LINEAR,
+ VK_IMAGE_USAGE_SAMPLED_BIT,
+ VK_IMAGE_LAYOUT_PREINITIALIZED,
+ VK_ACCESS_HOST_WRITE_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+
+ gsk_vulkan_image_upload_data (self, data, width, height, stride);
+
+ gsk_vulkan_uploader_add_image_barrier (uploader,
+ TRUE,
+ self,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ VK_ACCESS_SHADER_READ_BIT);
+
+ gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+ return self;
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_from_data (GskVulkanUploader *uploader,
+ guchar *data,
+ gsize width,
+ gsize height,
+ gsize stride)
+{
+ if (GSK_RENDER_MODE_CHECK (STAGING_BUFFER))
+ return gsk_vulkan_image_new_from_data_via_staging_buffer (uploader, data, width, height, stride);
+ if (GSK_RENDER_MODE_CHECK (STAGING_IMAGE))
+ return gsk_vulkan_image_new_from_data_via_staging_image (uploader, data, width, height, stride);
+ else
+ return gsk_vulkan_image_new_from_data_directly (uploader, data, width, height, stride);
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
+ VkImage image,
+ VkFormat format,
+ gsize width,
+ gsize height)
+{
+ GskVulkanImage *self;
+
+ self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
+
+ self->vulkan = g_object_ref (context);
+ self->width = width;
+ self->height = height;
+ self->vk_image = image;
+
+ gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+ return self;
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
+ gsize width,
+ gsize height)
+{
+ GskVulkanImage *self;
+
+
+ self = gsk_vulkan_image_new (context,
+ width,
+ height,
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+ return self;
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
+ gsize width,
+ gsize height)
+{
+ GskVulkanImage *self;
+
+ self = gsk_vulkan_image_new (context,
+ width,
+ height,
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ 0,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+ return self;
+}
+
+GskVulkanImage *
+gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
+ gsize width,
+ gsize height)
+{
+ GskVulkanImage *self;
+
+ self = gsk_vulkan_image_new (context,
+ width,
+ height,
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_SAMPLED_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ 0,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+ return self;
+}
+
+GdkTexture *
+gsk_vulkan_image_download (GskVulkanImage *self,
+ GskVulkanUploader *uploader)
+{
+ GskVulkanBuffer *buffer;
+ GdkTexture *texture;
+ guchar *mem;
+
+ gsk_vulkan_uploader_add_image_barrier (uploader,
+ FALSE,
+ self,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ VK_ACCESS_TRANSFER_READ_BIT);
+
+ buffer = gsk_vulkan_buffer_new_download (self->vulkan, self->width * self->height * 4);
+
+ vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader),
+ self->vk_image,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ gsk_vulkan_buffer_get_buffer (buffer),
+ 1,
+ (VkBufferImageCopy[1]) {
+ {
+ .bufferOffset = 0,
+ .imageSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ },
+ .imageOffset = { 0, 0, 0 },
+ .imageExtent = {
+ .width = self->width,
+ .height = self->height,
+ .depth = 1
+ }
+ }
+ });
+
+ gsk_vulkan_uploader_upload (uploader);
+
+ GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
+
+ mem = gsk_vulkan_buffer_map (buffer);
+ texture = gdk_texture_new_for_data (mem, self->width, self->height, self->width * 4);
+ gsk_vulkan_buffer_unmap (buffer);
+ gsk_vulkan_buffer_free (buffer);
+
+ return texture;
+}
+
+void
+gsk_vulkan_image_upload_regions (GskVulkanImage *self,
+ GskVulkanUploader *uploader,
+ guint num_regions,
+ GskImageRegion *regions)
+{
+ GskVulkanBuffer *staging;
+ guchar *mem;
+ guchar *m;
+ gsize size;
+ gsize offset;
+ VkBufferImageCopy *bufferImageCopy;
+
+ size = 0;
+ for (int i = 0; i < num_regions; i++)
+ size += regions[i].width * regions[i].height * 4;
+
+ staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, size);
+ mem = gsk_vulkan_buffer_map (staging);
+
+ bufferImageCopy = alloca (sizeof (VkBufferImageCopy) * num_regions);
+ memset (bufferImageCopy, 0, sizeof (VkBufferImageCopy) * num_regions);
+
+ offset = 0;
+ for (int i = 0; i < num_regions; i++)
+ {
+ m = mem + offset;
+ if (regions[i].stride == regions[i].width * 4)
+ {
+ memcpy (m, regions[i].data, regions[i].stride * regions[i].height);
+ }
+ else
+ {
+ for (gsize r = 0; r < regions[i].height; i++)
+ memcpy (m + r * regions[i].width * 4, regions[i].data + r * regions[i].stride, regions[i].width * 4);
+ }
+
+ bufferImageCopy[i].bufferOffset = offset;
+ bufferImageCopy[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ bufferImageCopy[i].imageSubresource.mipLevel = 0;
+ bufferImageCopy[i].imageSubresource.baseArrayLayer = 0;
+ bufferImageCopy[i].imageSubresource.layerCount = 1;
+ bufferImageCopy[i].imageOffset.x = regions[i].x;
+ bufferImageCopy[i].imageOffset.y = regions[i].y;
+ bufferImageCopy[i].imageOffset.z = 0;
+ bufferImageCopy[i].imageExtent.width = regions[i].width;
+ bufferImageCopy[i].imageExtent.height = regions[i].height;
+ bufferImageCopy[i].imageExtent.depth = 1;
+
+ offset += regions[i].width * regions[i].height * 4;
+ }
+
+ gsk_vulkan_buffer_unmap (staging);
+
+ gsk_vulkan_uploader_add_image_barrier (uploader,
+ FALSE,
+ self,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+
+ vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
+ gsk_vulkan_buffer_get_buffer (staging),
+ self->vk_image,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ num_regions,
+ bufferImageCopy);
+
+ gsk_vulkan_uploader_add_image_barrier (uploader,
+ TRUE,
+ self,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ VK_ACCESS_SHADER_READ_BIT);
+
+ uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, staging);
+
+ gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+}
+
+static void
+gsk_vulkan_image_finalize (GObject *object)
+{
+ GskVulkanImage *self = GSK_VULKAN_IMAGE (object);
+
+ if (self->vk_image_view != VK_NULL_HANDLE)
+ {
+ vkDestroyImageView (gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_image_view,
+ NULL);
+ }
+
+ /* memory is NULL for for_swapchain() images, where we don't own
+ * the VkImage */
+ if (self->memory)
+ {
+ vkDestroyImage (gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_image,
+ NULL);
+
+ gsk_vulkan_memory_free (self->memory);
+ }
+
+ g_object_unref (self->vulkan);
+
+ G_OBJECT_CLASS (gsk_vulkan_image_parent_class)->finalize (object);
+}
+
+static void
+gsk_vulkan_image_class_init (GskVulkanImageClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_image_finalize;
+}
+
+static void
+gsk_vulkan_image_init (GskVulkanImage *self)
+{
+}
+
+gsize
+gsk_vulkan_image_get_width (GskVulkanImage *self)
+{
+ return self->width;
+}
+
+gsize
+gsk_vulkan_image_get_height (GskVulkanImage *self)
+{
+ return self->height;
+}
+
+VkImage
+gsk_vulkan_image_get_image (GskVulkanImage *self)
+{
+ return self->vk_image;
+}
+
+VkImageView
+gsk_vulkan_image_get_image_view (GskVulkanImage *self)
+{
+ return self->vk_image_view;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_IMAGE_PRIVATE_H__
+#define __GSK_VULKAN_IMAGE_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+#include "gskvulkancommandpoolprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanUploader GskVulkanUploader;
+
+#define GSK_TYPE_VULKAN_IMAGE (gsk_vulkan_image_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanImage, gsk_vulkan_image, GSK, VULKAN_IMAGE, GObject)
+
+GskVulkanUploader * gsk_vulkan_uploader_new (GdkVulkanContext *context,
+ GskVulkanCommandPool *command_pool);
+void gsk_vulkan_uploader_free (GskVulkanUploader *self);
+
+void gsk_vulkan_uploader_reset (GskVulkanUploader *self);
+void gsk_vulkan_uploader_upload (GskVulkanUploader *self);
+
+GskVulkanImage * gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
+ VkImage image,
+ VkFormat format,
+ gsize width,
+ gsize height);
+GskVulkanImage * gsk_vulkan_image_new_from_data (GskVulkanUploader *uploader,
+ guchar *data,
+ gsize width,
+ gsize height,
+ gsize stride);
+
+typedef struct {
+ guchar *data;
+ gsize width;
+ gsize height;
+ gsize stride;
+ gsize x;
+ gsize y;
+} GskImageRegion;
+
+void gsk_vulkan_image_upload_regions (GskVulkanImage *image,
+ GskVulkanUploader *uploader,
+ guint num_regions,
+ GskImageRegion *regions);
+GskVulkanImage * gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
+ gsize width,
+ gsize height);
+GskVulkanImage * gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
+ gsize width,
+ gsize height);
+GskVulkanImage * gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
+ gsize width,
+ gsize height);
+
+GdkTexture * gsk_vulkan_image_download (GskVulkanImage *self,
+ GskVulkanUploader *uploader);
+
+gsize gsk_vulkan_image_get_width (GskVulkanImage *self);
+gsize gsk_vulkan_image_get_height (GskVulkanImage *self);
+VkImage gsk_vulkan_image_get_image (GskVulkanImage *self);
+VkImageView gsk_vulkan_image_get_image_view (GskVulkanImage *self);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_IMAGE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanlineargradientpipelineprivate.h"
+
+struct _GskVulkanLinearGradientPipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanLinearGradientInstance GskVulkanLinearGradientInstance;
+
+struct _GskVulkanLinearGradientInstance
+{
+ float rect[4];
+ float start[2];
+ float end[2];
+ gint32 repeating;
+ gint32 stop_count;
+ float offsets[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS];
+ float colors[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS][4];
+};
+
+G_DEFINE_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanLinearGradientInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = 0,
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, start),
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, end),
+ },
+ {
+ .location = 3,
+ .binding = 0,
+ .format = VK_FORMAT_R32_SINT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, repeating),
+ },
+ {
+ .location = 4,
+ .binding = 0,
+ .format = VK_FORMAT_R32_SINT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, stop_count),
+ },
+ {
+ .location = 5,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets),
+ },
+ {
+ .location = 6,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets) + sizeof (float) * 4,
+ },
+ {
+ .location = 7,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[0]),
+ },
+ {
+ .location = 8,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[1]),
+ },
+ {
+ .location = 9,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[2]),
+ },
+ {
+ .location = 10,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[3]),
+ },
+ {
+ .location = 11,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[4]),
+ },
+ {
+ .location = 12,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[5]),
+ },
+ {
+ .location = 13,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[6]),
+ },
+ {
+ .location = 14,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[7]),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_linear_gradient_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanLinearGradientPipeline *self = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_linear_gradient_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_linear_gradient_pipeline_class_init (GskVulkanLinearGradientPipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_linear_gradient_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_linear_gradient_pipeline_init (GskVulkanLinearGradientPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_linear_gradient_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GskVulkanLinearGradientPipeline *pipeline)
+{
+ return sizeof (GskVulkanLinearGradientInstance);
+}
+
+void
+gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradientPipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const graphene_point_t *start,
+ const graphene_point_t *end,
+ gboolean repeating,
+ gsize n_stops,
+ const GskColorStop *stops)
+{
+ GskVulkanLinearGradientInstance *instance = (GskVulkanLinearGradientInstance *) data;
+ gsize i;
+
+ if (n_stops > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
+ {
+ g_warning ("Only %u color stops supported.", GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
+ n_stops = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS;
+ }
+ instance->rect[0] = rect->origin.x;
+ instance->rect[1] = rect->origin.y;
+ instance->rect[2] = rect->size.width;
+ instance->rect[3] = rect->size.height;
+ instance->start[0] = start->x;
+ instance->start[1] = start->y;
+ instance->end[0] = end->x;
+ instance->end[1] = end->y;
+ instance->repeating = repeating;
+ instance->stop_count = n_stops;
+ for (i = 0; i < n_stops; i++)
+ {
+ instance->offsets[i] = stops[i].offset;
+ instance->colors[i][0] = stops[i].color.red;
+ instance->colors[i][1] = stops[i].color.green;
+ instance->colors[i][2] = stops[i].color.blue;
+ instance->colors[i][3] = stops[i].color.alpha;
+ }
+}
+
+gsize
+gsk_vulkan_linear_gradient_pipeline_draw (GskVulkanLinearGradientPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskrendernode.h"
+
+G_BEGIN_DECLS
+
+#define GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS 8
+
+typedef struct _GskVulkanLinearGradientPipelineLayout GskVulkanLinearGradientPipelineLayout;
+
+#define GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE (gsk_vulkan_linear_gradient_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK, VULKAN_LINEAR_GRADIENT_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_linear_gradient_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_linear_gradient_pipeline_count_vertex_data
+ (GskVulkanLinearGradientPipeline*pipeline);
+void gsk_vulkan_linear_gradient_pipeline_collect_vertex_data
+ (GskVulkanLinearGradientPipeline*pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const graphene_point_t *start,
+ const graphene_point_t *end,
+ gboolean repeating,
+ gsize n_stops,
+ const GskColorStop *stops);
+gsize gsk_vulkan_linear_gradient_pipeline_draw (GskVulkanLinearGradientPipeline*pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanmemoryprivate.h"
+
+struct _GskVulkanMemory
+{
+ GdkVulkanContext *vulkan;
+
+ gsize size;
+
+ VkDeviceMemory vk_memory;
+};
+
+GskVulkanMemory *
+gsk_vulkan_memory_new (GdkVulkanContext *context,
+ uint32_t allowed_types,
+ VkMemoryPropertyFlags flags,
+ gsize size)
+{
+ VkPhysicalDeviceMemoryProperties properties;
+ GskVulkanMemory *self;
+ uint32_t i;
+
+ self = g_slice_new0 (GskVulkanMemory);
+
+ self->vulkan = g_object_ref (context);
+ self->size = size;
+
+ vkGetPhysicalDeviceMemoryProperties (gdk_vulkan_context_get_physical_device (context),
+ &properties);
+
+ for (i = 0; i < properties.memoryTypeCount; i++)
+ {
+ if (!(allowed_types & (1 << i)))
+ continue;
+
+ if ((properties.memoryTypes[i].propertyFlags & flags) == flags)
+ break;
+ }
+
+ g_assert (i < properties.memoryTypeCount);
+
+ GSK_VK_CHECK (vkAllocateMemory, gdk_vulkan_context_get_device (context),
+ &(VkMemoryAllocateInfo) {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .allocationSize = size,
+ .memoryTypeIndex = i
+ },
+ NULL,
+ &self->vk_memory);
+
+ return self;
+}
+
+void
+gsk_vulkan_memory_free (GskVulkanMemory *self)
+{
+ vkFreeMemory (gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_memory,
+ NULL);
+
+ g_object_unref (self->vulkan);
+
+ g_slice_free (GskVulkanMemory, self);
+}
+
+VkDeviceMemory
+gsk_vulkan_memory_get_device_memory (GskVulkanMemory *self)
+{
+ return self->vk_memory;
+}
+
+guchar *
+gsk_vulkan_memory_map (GskVulkanMemory *self)
+{
+ void *data;
+
+ GSK_VK_CHECK (vkMapMemory, gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_memory,
+ 0,
+ self->size,
+ 0,
+ &data);
+
+ return data;
+}
+
+void
+gsk_vulkan_memory_unmap (GskVulkanMemory *self)
+{
+ vkUnmapMemory (gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_memory);
+}
+
--- /dev/null
+#ifndef __GSK_VULKAN_MEMORY_PRIVATE_H__
+#define __GSK_VULKAN_MEMORY_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanMemory GskVulkanMemory;
+
+GskVulkanMemory * gsk_vulkan_memory_new (GdkVulkanContext *context,
+ uint32_t allowed_types,
+ VkMemoryPropertyFlags properties,
+ gsize size);
+void gsk_vulkan_memory_free (GskVulkanMemory *memory);
+
+VkDeviceMemory gsk_vulkan_memory_get_device_memory (GskVulkanMemory *self);
+
+guchar * gsk_vulkan_memory_map (GskVulkanMemory *self);
+void gsk_vulkan_memory_unmap (GskVulkanMemory *self);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_MEMORY_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanpipelineprivate.h"
+
+#include "gskvulkanpushconstantsprivate.h"
+#include "gskvulkanshaderprivate.h"
+
+#include <graphene.h>
+
+typedef struct _GskVulkanPipelinePrivate GskVulkanPipelinePrivate;
+
+struct _GskVulkanPipelinePrivate
+{
+ GObject parent_instance;
+
+ GdkVulkanContext *context;
+
+ VkPipeline pipeline;
+ VkPipelineLayout layout;
+
+ GskVulkanShader *vertex_shader;
+ GskVulkanShader *fragment_shader;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GskVulkanPipeline, gsk_vulkan_pipeline, G_TYPE_OBJECT)
+
+static void
+gsk_vulkan_pipeline_finalize (GObject *gobject)
+{
+ GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (GSK_VULKAN_PIPELINE (gobject));
+ VkDevice device;
+
+ device = gdk_vulkan_context_get_device (priv->context);
+
+ vkDestroyPipeline (device,
+ priv->pipeline,
+ NULL);
+
+ g_clear_pointer (&priv->fragment_shader, gsk_vulkan_shader_free);
+ g_clear_pointer (&priv->vertex_shader, gsk_vulkan_shader_free);
+
+ G_OBJECT_CLASS (gsk_vulkan_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_pipeline_class_init (GskVulkanPipelineClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_pipeline_finalize;
+}
+
+static void
+gsk_vulkan_pipeline_init (GskVulkanPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_pipeline_new (GType pipeline_type,
+ GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new_full (pipeline_type, context, layout, shader_name, render_pass,
+ VK_BLEND_FACTOR_ONE,
+ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
+}
+
+GskVulkanPipeline *
+gsk_vulkan_pipeline_new_full (GType pipeline_type,
+ GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass,
+ VkBlendFactor srcBlendFactor,
+ VkBlendFactor dstBlendFactor)
+{
+ GskVulkanPipelinePrivate *priv;
+ GskVulkanPipeline *self;
+ VkDevice device;
+
+ g_return_val_if_fail (g_type_is_a (pipeline_type, GSK_TYPE_VULKAN_PIPELINE), NULL);
+ g_return_val_if_fail (layout != VK_NULL_HANDLE, NULL);
+ g_return_val_if_fail (shader_name != NULL, NULL);
+ g_return_val_if_fail (render_pass != VK_NULL_HANDLE, NULL);
+
+ self = g_object_new (pipeline_type, NULL);
+
+ priv = gsk_vulkan_pipeline_get_instance_private (self);
+
+ device = gdk_vulkan_context_get_device (context);
+
+ priv->context = context;
+ priv->layout = layout;
+
+ priv->vertex_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_VERTEX, shader_name, NULL);
+ priv->fragment_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_FRAGMENT, shader_name, NULL);
+
+ GSK_VK_CHECK (vkCreateGraphicsPipelines, device,
+ VK_NULL_HANDLE,
+ 1,
+ &(VkGraphicsPipelineCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .stageCount = 2,
+ .pStages = (VkPipelineShaderStageCreateInfo[2]) {
+ GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->vertex_shader),
+ GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->fragment_shader)
+ },
+ .pVertexInputState = GSK_VULKAN_PIPELINE_GET_CLASS (self)->get_input_state_create_info (self),
+ .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ .primitiveRestartEnable = VK_FALSE,
+ },
+ .pTessellationState = NULL,
+ .pViewportState = &(VkPipelineViewportStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .viewportCount = 1,
+ .scissorCount = 1
+ },
+ .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .depthClampEnable = VK_FALSE,
+ .rasterizerDiscardEnable = VK_FALSE,
+ .polygonMode = VK_POLYGON_MODE_FILL,
+ .cullMode = VK_CULL_MODE_BACK_BIT,
+ .frontFace = VK_FRONT_FACE_CLOCKWISE,
+ .lineWidth = 1.0f,
+ },
+ .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .rasterizationSamples = 1,
+ },
+ .pDepthStencilState = &(VkPipelineDepthStencilStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
+ },
+ .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+ .attachmentCount = 1,
+ .pAttachments = (VkPipelineColorBlendAttachmentState []) {
+ {
+ .blendEnable = VK_TRUE,
+ .colorBlendOp = VK_BLEND_OP_ADD,
+ .srcColorBlendFactor = srcBlendFactor,
+ .dstColorBlendFactor = dstBlendFactor,
+ .alphaBlendOp = VK_BLEND_OP_ADD,
+ .srcAlphaBlendFactor = srcBlendFactor,
+ .dstAlphaBlendFactor = dstBlendFactor,
+ .colorWriteMask = VK_COLOR_COMPONENT_A_BIT
+ | VK_COLOR_COMPONENT_R_BIT
+ | VK_COLOR_COMPONENT_G_BIT
+ | VK_COLOR_COMPONENT_B_BIT
+ },
+ }
+ },
+ .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .dynamicStateCount = 2,
+ .pDynamicStates = (VkDynamicState[2]) {
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR
+ },
+ },
+ .layout = priv->layout,
+ .renderPass = render_pass,
+ .subpass = 0,
+ .basePipelineHandle = VK_NULL_HANDLE,
+ .basePipelineIndex = -1,
+ },
+ NULL,
+ &priv->pipeline);
+
+ return self;
+}
+
+VkPipeline
+gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self)
+{
+ GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (self);
+
+ return priv->pipeline;
+}
+
+VkPipelineLayout
+gsk_vulkan_pipeline_get_pipeline_layout (GskVulkanPipeline *self)
+{
+ GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (self);
+
+ return priv->layout;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_PIPELINE_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+#include "gskdebugprivate.h"
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_VULKAN_PIPELINE (gsk_vulkan_pipeline_get_type ())
+
+G_DECLARE_DERIVABLE_TYPE (GskVulkanPipeline, gsk_vulkan_pipeline, GSK, VULKAN_PIPELINE, GObject)
+
+struct _GskVulkanPipelineClass
+{
+ GObjectClass parent_class;
+
+ const VkPipelineVertexInputStateCreateInfo *
+ (* get_input_state_create_info) (GskVulkanPipeline *self);
+};
+
+static inline VkResult
+gsk_vulkan_handle_result (VkResult res,
+ const char *called_function)
+{
+ if (res != VK_SUCCESS)
+ {
+ GSK_NOTE (VULKAN,g_printerr ("%s(): %s (%d)\n", called_function, gdk_vulkan_strerror (res), res));
+ }
+ return res;
+}
+
+#define GSK_VK_CHECK(func, ...) gsk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func))
+
+GskVulkanPipeline * gsk_vulkan_pipeline_new (GType pipeline_type,
+ GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+GskVulkanPipeline * gsk_vulkan_pipeline_new_full (GType pipeline_type,
+ GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass,
+ VkBlendFactor srcBlendFactor,
+ VkBlendFactor dstBlendFactor);
+
+VkPipeline gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self);
+VkPipelineLayout gsk_vulkan_pipeline_get_pipeline_layout (GskVulkanPipeline *self);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanpushconstantsprivate.h"
+
+#include "gskroundedrectprivate.h"
+
+typedef struct _GskVulkanPushConstantsWire GskVulkanPushConstantsWire;
+
+struct _GskVulkanPushConstantsWire
+{
+ struct {
+ float mvp[16];
+ float clip[12];
+ } common;
+};
+
+void
+gsk_vulkan_push_constants_init (GskVulkanPushConstants *constants,
+ const graphene_matrix_t *mvp,
+ const graphene_rect_t *viewport)
+{
+ graphene_matrix_init_from_matrix (&constants->mvp, mvp);
+ gsk_vulkan_clip_init_empty (&constants->clip, viewport);
+}
+
+void
+gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants *self,
+ const GskVulkanPushConstants *src)
+{
+ *self = *src;
+}
+
+gboolean
+gsk_vulkan_push_constants_transform (GskVulkanPushConstants *self,
+ const GskVulkanPushConstants *src,
+ const graphene_matrix_t *transform,
+ const graphene_rect_t *viewport)
+
+{
+ if (!gsk_vulkan_clip_transform (&self->clip, &src->clip, transform, viewport))
+ return FALSE;
+
+ graphene_matrix_multiply (transform, &src->mvp, &self->mvp);
+ return TRUE;
+}
+
+gboolean
+gsk_vulkan_push_constants_intersect_rect (GskVulkanPushConstants *self,
+ const GskVulkanPushConstants *src,
+ const graphene_rect_t *rect)
+{
+ if (!gsk_vulkan_clip_intersect_rect (&self->clip, &src->clip, rect))
+ return FALSE;
+
+ graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
+ return TRUE;
+}
+
+gboolean
+gsk_vulkan_push_constants_intersect_rounded (GskVulkanPushConstants *self,
+ const GskVulkanPushConstants *src,
+ const GskRoundedRect *rect)
+{
+ if (!gsk_vulkan_clip_intersect_rounded_rect (&self->clip, &src->clip, rect))
+ return FALSE;
+
+ graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
+ return TRUE;
+}
+
+static void
+gsk_vulkan_push_constants_wire_init (GskVulkanPushConstantsWire *wire,
+ const GskVulkanPushConstants *self)
+{
+ graphene_matrix_to_float (&self->mvp, wire->common.mvp);
+ gsk_rounded_rect_to_float (&self->clip.rect, wire->common.clip);
+}
+
+void
+gsk_vulkan_push_constants_push (const GskVulkanPushConstants *self,
+ VkCommandBuffer command_buffer,
+ VkPipelineLayout pipeline_layout)
+{
+ GskVulkanPushConstantsWire wire;
+
+ gsk_vulkan_push_constants_wire_init (&wire, self);
+
+ vkCmdPushConstants (command_buffer,
+ pipeline_layout,
+ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
+ G_STRUCT_OFFSET (GskVulkanPushConstantsWire, common),
+ sizeof (wire.common),
+ &wire.common);
+}
+
+uint32_t
+gsk_vulkan_push_constants_get_range_count (void)
+{
+ return 1;
+}
+
+const VkPushConstantRange *
+gsk_vulkan_push_constants_get_ranges (void)
+{
+ static const VkPushConstantRange ranges[1] = {
+ {
+ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
+ .offset = G_STRUCT_OFFSET (GskVulkanPushConstantsWire, common),
+ .size = sizeof (((GskVulkanPushConstantsWire *) 0)->common)
+ }
+ };
+
+ return ranges;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__
+#define __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <graphene.h>
+#include "gskvulkanclipprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanPushConstants GskVulkanPushConstants;
+
+struct _GskVulkanPushConstants
+{
+ graphene_matrix_t mvp;
+ GskVulkanClip clip;
+};
+
+const VkPushConstantRange *
+ gsk_vulkan_push_constants_get_ranges (void) G_GNUC_PURE;
+uint32_t gsk_vulkan_push_constants_get_range_count (void) G_GNUC_PURE;
+
+void gsk_vulkan_push_constants_init (GskVulkanPushConstants *constants,
+ const graphene_matrix_t *mvp,
+ const graphene_rect_t *viewport);
+void gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants *self,
+ const GskVulkanPushConstants *src);
+
+gboolean gsk_vulkan_push_constants_transform (GskVulkanPushConstants *self,
+ const GskVulkanPushConstants *src,
+ const graphene_matrix_t *transform,
+ const graphene_rect_t *viewport);
+gboolean gsk_vulkan_push_constants_intersect_rect (GskVulkanPushConstants *self,
+ const GskVulkanPushConstants *src,
+ const graphene_rect_t *rect);
+gboolean gsk_vulkan_push_constants_intersect_rounded (GskVulkanPushConstants *self,
+ const GskVulkanPushConstants *src,
+ const GskRoundedRect *rect);
+
+void gsk_vulkan_push_constants_push (const GskVulkanPushConstants *self,
+ VkCommandBuffer command_buffer,
+ VkPipelineLayout pipeline_layout);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_PUSH_CONSTANTS_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskprivate.h"
+
+#include "gskvulkanrenderprivate.h"
+
+#include "gskrendererprivate.h"
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkancommandpoolprivate.h"
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrenderpassprivate.h"
+
+#include "gskvulkanblendmodepipelineprivate.h"
+#include "gskvulkanblurpipelineprivate.h"
+#include "gskvulkanborderpipelineprivate.h"
+#include "gskvulkanboxshadowpipelineprivate.h"
+#include "gskvulkancolorpipelineprivate.h"
+#include "gskvulkancolortextpipelineprivate.h"
+#include "gskvulkancrossfadepipelineprivate.h"
+#include "gskvulkaneffectpipelineprivate.h"
+#include "gskvulkanlineargradientpipelineprivate.h"
+#include "gskvulkantextpipelineprivate.h"
+#include "gskvulkantexturepipelineprivate.h"
+#include "gskvulkanpushconstantsprivate.h"
+
+#define DESCRIPTOR_POOL_MAXSETS 128
+#define DESCRIPTOR_POOL_MAXSETS_INCREASE 128
+
+struct _GskVulkanRender
+{
+ GskRenderer *renderer;
+ GdkVulkanContext *vulkan;
+
+ int scale_factor;
+ graphene_rect_t viewport;
+ cairo_region_t *clip;
+
+ GHashTable *framebuffers;
+ GskVulkanCommandPool *command_pool;
+ VkFence fence;
+ VkRenderPass render_pass;
+ VkDescriptorSetLayout descriptor_set_layout;
+ VkPipelineLayout pipeline_layout[3]; /* indexed by number of textures */
+ GskVulkanUploader *uploader;
+
+ GHashTable *descriptor_set_indexes;
+ VkDescriptorPool descriptor_pool;
+ uint32_t descriptor_pool_maxsets;
+ VkDescriptorSet *descriptor_sets;
+ gsize n_descriptor_sets;
+ GskVulkanPipeline *pipelines[GSK_VULKAN_N_PIPELINES];
+
+ GskVulkanImage *target;
+
+ VkSampler sampler;
+ VkSampler repeating_sampler;
+
+ GList *render_passes;
+ GSList *cleanup_images;
+
+ GQuark render_pass_counter;
+ GQuark gpu_time_timer;
+};
+
+static void
+gsk_vulkan_render_setup (GskVulkanRender *self,
+ GskVulkanImage *target,
+ const graphene_rect_t *rect)
+{
+ GdkWindow *window = gsk_renderer_get_window (self->renderer);
+
+ self->target = g_object_ref (target);
+
+ if (rect)
+ {
+ self->viewport = *rect;
+ self->scale_factor = 1;
+ self->clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
+ 0, 0,
+ gsk_vulkan_image_get_width (target),
+ gsk_vulkan_image_get_height (target)
+ });
+ }
+ else
+ {
+ self->scale_factor = gdk_window_get_scale_factor (gsk_renderer_get_window (self->renderer));
+ self->viewport = GRAPHENE_RECT_INIT (0, 0,
+ gdk_window_get_width (window) * self->scale_factor,
+ gdk_window_get_height (window) * self->scale_factor);
+ self->clip = gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (self->renderer));
+ }
+}
+
+static guint desc_set_index_hash (gconstpointer v);
+static gboolean desc_set_index_equal (gconstpointer v1, gconstpointer v2);
+
+GskVulkanRender *
+gsk_vulkan_render_new (GskRenderer *renderer,
+ GdkVulkanContext *context)
+{
+ GskVulkanRender *self;
+ VkDevice device;
+
+ self = g_slice_new0 (GskVulkanRender);
+
+ self->vulkan = context;
+ self->renderer = renderer;
+ self->framebuffers = g_hash_table_new (g_direct_hash, g_direct_equal);
+ self->descriptor_set_indexes = g_hash_table_new_full (desc_set_index_hash, desc_set_index_equal, NULL, g_free);
+
+ device = gdk_vulkan_context_get_device (self->vulkan);
+
+ self->command_pool = gsk_vulkan_command_pool_new (self->vulkan);
+ GSK_VK_CHECK (vkCreateFence, device,
+ &(VkFenceCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+ .flags = VK_FENCE_CREATE_SIGNALED_BIT
+ },
+ NULL,
+ &self->fence);
+
+ self->descriptor_pool_maxsets = DESCRIPTOR_POOL_MAXSETS;
+ GSK_VK_CHECK (vkCreateDescriptorPool, device,
+ &(VkDescriptorPoolCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+ .maxSets = self->descriptor_pool_maxsets,
+ .poolSizeCount = 1,
+ .pPoolSizes = (VkDescriptorPoolSize[1]) {
+ {
+ .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .descriptorCount = self->descriptor_pool_maxsets
+ }
+ }
+ },
+ NULL,
+ &self->descriptor_pool);
+
+ GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
+ &(VkRenderPassCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+ .attachmentCount = 1,
+ .pAttachments = (VkAttachmentDescription[]) {
+ {
+ .format = gdk_vulkan_context_get_image_format (self->vulkan),
+ .samples = VK_SAMPLE_COUNT_1_BIT,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+ .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ }
+ },
+ .subpassCount = 1,
+ .pSubpasses = (VkSubpassDescription []) {
+ {
+ .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+ .inputAttachmentCount = 0,
+ .colorAttachmentCount = 1,
+ .pColorAttachments = (VkAttachmentReference []) {
+ {
+ .attachment = 0,
+ .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ }
+ },
+ .pResolveAttachments = (VkAttachmentReference []) {
+ {
+ .attachment = VK_ATTACHMENT_UNUSED,
+ .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ }
+ },
+ .pDepthStencilAttachment = NULL,
+ }
+ },
+ .dependencyCount = 0
+ },
+ NULL,
+ &self->render_pass);
+
+ GSK_VK_CHECK (vkCreateDescriptorSetLayout, device,
+ &(VkDescriptorSetLayoutCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ .bindingCount = 1,
+ .pBindings = (VkDescriptorSetLayoutBinding[1]) {
+ {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
+ }
+ }
+ },
+ NULL,
+ &self->descriptor_set_layout);
+
+ for (guint i = 0; i < 3; i++)
+ {
+ VkDescriptorSetLayout layouts[3] = {
+ self->descriptor_set_layout,
+ self->descriptor_set_layout,
+ self->descriptor_set_layout
+ };
+
+ GSK_VK_CHECK (vkCreatePipelineLayout, device,
+ &(VkPipelineLayoutCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .setLayoutCount = i,
+ .pSetLayouts = layouts,
+ .pushConstantRangeCount = gsk_vulkan_push_constants_get_range_count (),
+ .pPushConstantRanges = gsk_vulkan_push_constants_get_ranges ()
+ },
+ NULL,
+ &self->pipeline_layout[i]);
+ }
+
+ GSK_VK_CHECK (vkCreateSampler, device,
+ &(VkSamplerCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+ .magFilter = VK_FILTER_LINEAR,
+ .minFilter = VK_FILTER_LINEAR,
+ .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
+ .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
+ .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+ .unnormalizedCoordinates = VK_FALSE,
+ .maxAnisotropy = 1.0,
+ },
+ NULL,
+ &self->sampler);
+
+ GSK_VK_CHECK (vkCreateSampler, device,
+ &(VkSamplerCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+ .magFilter = VK_FILTER_LINEAR,
+ .minFilter = VK_FILTER_LINEAR,
+ .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+ .unnormalizedCoordinates = VK_FALSE,
+ .maxAnisotropy = 1.0,
+ },
+ NULL,
+ &self->repeating_sampler);
+
+ self->uploader = gsk_vulkan_uploader_new (self->vulkan, self->command_pool);
+
+#ifdef G_ENABLE_DEBUG
+ self->render_pass_counter = g_quark_from_static_string ("render-passes");
+ self->gpu_time_timer = g_quark_from_static_string ("gpu-time");
+#endif
+
+ return self;
+}
+
+typedef struct {
+ VkFramebuffer framebuffer;
+} HashFramebufferEntry;
+
+static void
+gsk_vulkan_render_remove_framebuffer_from_image (gpointer data,
+ GObject *image)
+{
+ GskVulkanRender *self = data;
+ HashFramebufferEntry *fb;
+
+ fb = g_hash_table_lookup (self->framebuffers, image);
+ g_hash_table_remove (self->framebuffers, image);
+
+ vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
+ fb->framebuffer,
+ NULL);
+
+ g_slice_free (HashFramebufferEntry, fb);
+}
+
+VkFramebuffer
+gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
+ GskVulkanImage *image)
+{
+ HashFramebufferEntry *fb;
+
+ fb = g_hash_table_lookup (self->framebuffers, image);
+ if (fb)
+ return fb->framebuffer;
+
+ fb = g_slice_new0 (HashFramebufferEntry);
+ GSK_VK_CHECK (vkCreateFramebuffer, gdk_vulkan_context_get_device (self->vulkan),
+ &(VkFramebufferCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+ .renderPass = self->render_pass,
+ .attachmentCount = 1,
+ .pAttachments = (VkImageView[1]) {
+ gsk_vulkan_image_get_image_view (image)
+ },
+ .width = gsk_vulkan_image_get_width (image),
+ .height = gsk_vulkan_image_get_height (image),
+ .layers = 1
+ },
+ NULL,
+ &fb->framebuffer);
+ g_hash_table_insert (self->framebuffers, image, fb);
+ g_object_weak_ref (G_OBJECT (image), gsk_vulkan_render_remove_framebuffer_from_image, self);
+
+ return fb->framebuffer;
+}
+
+void
+gsk_vulkan_render_add_cleanup_image (GskVulkanRender *self,
+ GskVulkanImage *image)
+{
+ self->cleanup_images = g_slist_prepend (self->cleanup_images, image);
+}
+
+void
+gsk_vulkan_render_add_render_pass (GskVulkanRender *self,
+ GskVulkanRenderPass *pass)
+{
+ self->render_passes = g_list_prepend (self->render_passes, pass);
+
+#ifdef G_ENABLE_DEBUG
+ gsk_profiler_counter_inc (gsk_renderer_get_profiler (self->renderer), self->render_pass_counter);
+#endif
+}
+
+void
+gsk_vulkan_render_add_node (GskVulkanRender *self,
+ GskRenderNode *node)
+{
+ GskVulkanRenderPass *pass;
+ graphene_matrix_t mv;
+
+ graphene_matrix_init_scale (&mv, self->scale_factor, self->scale_factor, 1.0);
+
+ pass = gsk_vulkan_render_pass_new (self->vulkan,
+ self->target,
+ self->scale_factor,
+ &mv,
+ &self->viewport,
+ self->clip,
+ VK_NULL_HANDLE);
+
+ gsk_vulkan_render_add_render_pass (self, pass);
+
+ gsk_vulkan_render_pass_add (pass, self, node);
+}
+
+void
+gsk_vulkan_render_upload (GskVulkanRender *self)
+{
+ GList *l;
+
+ /* gsk_vulkan_render_pass_upload may call gsk_vulkan_render_add_node_for_texture,
+ * prepending new render passes to the list. Therefore, we walk the list from
+ * the end.
+ */
+ for (l = g_list_last (self->render_passes); l; l = l->prev)
+ {
+ GskVulkanRenderPass *pass = l->data;
+ gsk_vulkan_render_pass_upload (pass, self, self->uploader);
+ }
+
+ gsk_vulkan_uploader_upload (self->uploader);
+}
+
+GskVulkanPipeline *
+gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
+ GskVulkanPipelineType type)
+{
+ static const struct {
+ const char *name;
+ guint num_textures;
+ GskVulkanPipeline * (* create_func) (GdkVulkanContext *context, VkPipelineLayout layout, const char *name, VkRenderPass render_pass);
+ } pipeline_info[GSK_VULKAN_N_PIPELINES] = {
+ { "texture", 1, gsk_vulkan_texture_pipeline_new },
+ { "texture-clip", 1, gsk_vulkan_texture_pipeline_new },
+ { "texture-clip-rounded", 1, gsk_vulkan_texture_pipeline_new },
+ { "color", 0, gsk_vulkan_color_pipeline_new },
+ { "color-clip", 0, gsk_vulkan_color_pipeline_new },
+ { "color-clip-rounded", 0, gsk_vulkan_color_pipeline_new },
+ { "linear", 0, gsk_vulkan_linear_gradient_pipeline_new },
+ { "linear-clip", 0, gsk_vulkan_linear_gradient_pipeline_new },
+ { "linear-clip-rounded", 0, gsk_vulkan_linear_gradient_pipeline_new },
+ { "color-matrix", 1, gsk_vulkan_effect_pipeline_new },
+ { "color-matrix-clip", 1, gsk_vulkan_effect_pipeline_new },
+ { "color-matrix-clip-rounded", 1, gsk_vulkan_effect_pipeline_new },
+ { "border", 0, gsk_vulkan_border_pipeline_new },
+ { "border-clip", 0, gsk_vulkan_border_pipeline_new },
+ { "border-clip-rounded", 0, gsk_vulkan_border_pipeline_new },
+ { "inset-shadow", 0, gsk_vulkan_box_shadow_pipeline_new },
+ { "inset-shadow-clip", 0, gsk_vulkan_box_shadow_pipeline_new },
+ { "inset-shadow-clip-rounded", 0, gsk_vulkan_box_shadow_pipeline_new },
+ { "outset-shadow", 0, gsk_vulkan_box_shadow_pipeline_new },
+ { "outset-shadow-clip", 0, gsk_vulkan_box_shadow_pipeline_new },
+ { "outset-shadow-clip-rounded", 0, gsk_vulkan_box_shadow_pipeline_new },
+ { "blur", 1, gsk_vulkan_blur_pipeline_new },
+ { "blur-clip", 1, gsk_vulkan_blur_pipeline_new },
+ { "blur-clip-rounded", 1, gsk_vulkan_blur_pipeline_new },
+ { "mask", 1, gsk_vulkan_text_pipeline_new },
+ { "mask-clip", 1, gsk_vulkan_text_pipeline_new },
+ { "mask-clip-rounded", 1, gsk_vulkan_text_pipeline_new },
+ { "texture", 1, gsk_vulkan_color_text_pipeline_new },
+ { "texture-clip", 1, gsk_vulkan_color_text_pipeline_new },
+ { "texture-clip-rounded", 1, gsk_vulkan_color_text_pipeline_new },
+ { "crossfade", 2, gsk_vulkan_cross_fade_pipeline_new },
+ { "crossfade-clip", 2, gsk_vulkan_cross_fade_pipeline_new },
+ { "crossfade-clip-rounded", 2, gsk_vulkan_cross_fade_pipeline_new },
+ { "blendmode", 2, gsk_vulkan_blend_mode_pipeline_new },
+ { "blendmode-clip", 2, gsk_vulkan_blend_mode_pipeline_new },
+ { "blendmode-clip-rounded", 2, gsk_vulkan_blend_mode_pipeline_new },
+ };
+
+ g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);
+
+ if (self->pipelines[type] == NULL)
+ self->pipelines[type] = pipeline_info[type].create_func (self->vulkan,
+ self->pipeline_layout[pipeline_info[type].num_textures],
+ pipeline_info[type].name,
+ self->render_pass);
+
+ return self->pipelines[type];
+}
+
+VkDescriptorSet
+gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
+ gsize id)
+{
+ g_assert (id < self->n_descriptor_sets);
+
+ return self->descriptor_sets[id];
+}
+
+typedef struct {
+ gsize index;
+ GskVulkanImage *image;
+ gboolean repeat;
+} HashDescriptorSetIndexEntry;
+
+static guint
+desc_set_index_hash (gconstpointer v)
+{
+ const HashDescriptorSetIndexEntry *e = v;
+
+ return GPOINTER_TO_UINT (e->image) + e->repeat;
+}
+
+static gboolean
+desc_set_index_equal (gconstpointer v1, gconstpointer v2)
+{
+ const HashDescriptorSetIndexEntry *e1 = v1;
+ const HashDescriptorSetIndexEntry *e2 = v2;
+
+ return e1->image == e2->image && e1->repeat == e2->repeat;
+}
+
+gsize
+gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
+ GskVulkanImage *source,
+ gboolean repeat)
+{
+ HashDescriptorSetIndexEntry lookup;
+ HashDescriptorSetIndexEntry *entry;
+
+ g_assert (source != NULL);
+
+ lookup.image = source;
+ lookup.repeat = repeat;
+
+ entry = g_hash_table_lookup (self->descriptor_set_indexes, &lookup);
+ if (entry)
+ return entry->index;
+
+ entry = g_new (HashDescriptorSetIndexEntry, 1);
+ entry->image = source;
+ entry->repeat = repeat;
+ entry->index = g_hash_table_size (self->descriptor_set_indexes);
+ g_hash_table_add (self->descriptor_set_indexes, entry);
+
+ return entry->index;
+}
+
+static void
+gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self)
+{
+ GHashTableIter iter;
+ gpointer key;
+ VkDevice device;
+ GList *l;
+ guint i, needed_sets;
+
+ device = gdk_vulkan_context_get_device (self->vulkan);
+
+ for (l = self->render_passes; l; l = l->next)
+ {
+ GskVulkanRenderPass *pass = l->data;
+ gsk_vulkan_render_pass_reserve_descriptor_sets (pass, self);
+ }
+
+ needed_sets = g_hash_table_size (self->descriptor_set_indexes);
+ if (needed_sets > self->n_descriptor_sets)
+ {
+ if (needed_sets > self->descriptor_pool_maxsets)
+ {
+ guint added_sets = needed_sets - self->descriptor_pool_maxsets;
+ added_sets = added_sets + DESCRIPTOR_POOL_MAXSETS_INCREASE - 1;
+ added_sets -= added_sets % DESCRIPTOR_POOL_MAXSETS_INCREASE;
+
+ vkDestroyDescriptorPool (device,
+ self->descriptor_pool,
+ NULL);
+ self->descriptor_pool_maxsets += added_sets;
+ GSK_VK_CHECK (vkCreateDescriptorPool, device,
+ &(VkDescriptorPoolCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+ .maxSets = self->descriptor_pool_maxsets,
+ .poolSizeCount = 1,
+ .pPoolSizes = (VkDescriptorPoolSize[1]) {
+ {
+ .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .descriptorCount = self->descriptor_pool_maxsets
+ }
+ }
+ },
+ NULL,
+ &self->descriptor_pool);
+ }
+ else
+ {
+ GSK_VK_CHECK (vkResetDescriptorPool, device,
+ self->descriptor_pool,
+ 0);
+ }
+
+ self->n_descriptor_sets = needed_sets;
+ self->descriptor_sets = g_renew (VkDescriptorSet, self->descriptor_sets, needed_sets);
+ }
+
+ VkDescriptorSetLayout *layouts = g_newa (VkDescriptorSetLayout, needed_sets);
+ for (i = 0; i < needed_sets; i++)
+ layouts[i] = self->descriptor_set_layout;
+
+ GSK_VK_CHECK (vkAllocateDescriptorSets, device,
+ &(VkDescriptorSetAllocateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ .descriptorPool = self->descriptor_pool,
+ .descriptorSetCount = needed_sets,
+ .pSetLayouts = layouts
+ },
+ self->descriptor_sets);
+
+ g_hash_table_iter_init (&iter, self->descriptor_set_indexes);
+ while (g_hash_table_iter_next (&iter, &key, NULL))
+ {
+ HashDescriptorSetIndexEntry *entry = key;
+ GskVulkanImage *image = entry->image;
+ gsize id = entry->index;
+ gboolean repeat = entry->repeat;
+
+ vkUpdateDescriptorSets (device,
+ 1,
+ (VkWriteDescriptorSet[1]) {
+ {
+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ .dstSet = self->descriptor_sets[id],
+ .dstBinding = 0,
+ .dstArrayElement = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .pImageInfo = &(VkDescriptorImageInfo) {
+ .sampler = repeat ? self->repeating_sampler : self->sampler,
+ .imageView = gsk_vulkan_image_get_image_view (image),
+ .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+ }
+ }
+ },
+ 0, NULL);
+ }
+}
+
+void
+gsk_vulkan_render_draw (GskVulkanRender *self)
+{
+ GList *l;
+
+#ifdef G_ENABLE_DEBUG
+ if (GSK_RENDER_MODE_CHECK (SYNC))
+ gsk_profiler_timer_begin (gsk_renderer_get_profiler (self->renderer), self->gpu_time_timer);
+#endif
+
+ gsk_vulkan_render_prepare_descriptor_sets (self);
+
+ for (l = self->render_passes; l; l = l->next)
+ {
+ GskVulkanRenderPass *pass = l->data;
+ VkCommandBuffer command_buffer;
+ gsize wait_semaphore_count;
+ gsize signal_semaphore_count;
+ VkSemaphore *wait_semaphores;
+ VkSemaphore *signal_semaphores;
+
+ wait_semaphore_count = gsk_vulkan_render_pass_get_wait_semaphores (pass, &wait_semaphores);
+ signal_semaphore_count = gsk_vulkan_render_pass_get_signal_semaphores (pass, &signal_semaphores);
+
+ command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
+
+ gsk_vulkan_render_pass_draw (pass, self, 3, self->pipeline_layout, command_buffer);
+
+ gsk_vulkan_command_pool_submit_buffer (self->command_pool,
+ command_buffer,
+ wait_semaphore_count,
+ wait_semaphores,
+ signal_semaphore_count,
+ signal_semaphores,
+ l->next != NULL ? VK_NULL_HANDLE : self->fence);
+ }
+
+ if (GSK_RENDER_MODE_CHECK (SYNC))
+ {
+ GskProfiler *profiler;
+ gint64 gpu_time;
+
+ GSK_VK_CHECK (vkWaitForFences, gdk_vulkan_context_get_device (self->vulkan),
+ 1,
+ &self->fence,
+ VK_TRUE,
+ INT64_MAX);
+
+ profiler = gsk_renderer_get_profiler (self->renderer);
+ gpu_time = gsk_profiler_timer_end (profiler, self->gpu_time_timer);
+ gsk_profiler_timer_set (profiler, self->gpu_time_timer, gpu_time);
+ }
+}
+
+GdkTexture *
+gsk_vulkan_render_download_target (GskVulkanRender *self)
+{
+ gsk_vulkan_uploader_reset (self->uploader);
+
+ return gsk_vulkan_image_download (self->target, self->uploader);
+}
+
+static void
+gsk_vulkan_render_cleanup (GskVulkanRender *self)
+{
+ VkDevice device = gdk_vulkan_context_get_device (self->vulkan);
+
+ /* XXX: Wait for fence here or just in reset()? */
+ GSK_VK_CHECK (vkWaitForFences, device,
+ 1,
+ &self->fence,
+ VK_TRUE,
+ INT64_MAX);
+
+ GSK_VK_CHECK (vkResetFences, device,
+ 1,
+ &self->fence);
+
+ gsk_vulkan_uploader_reset (self->uploader);
+
+ gsk_vulkan_command_pool_reset (self->command_pool);
+
+ g_hash_table_remove_all (self->descriptor_set_indexes);
+ GSK_VK_CHECK (vkResetDescriptorPool, device,
+ self->descriptor_pool,
+ 0);
+
+ g_list_free_full (self->render_passes, (GDestroyNotify) gsk_vulkan_render_pass_free);
+ self->render_passes = NULL;
+ g_slist_free_full (self->cleanup_images, g_object_unref);
+ self->cleanup_images = NULL;
+
+ g_clear_pointer (&self->clip, cairo_region_destroy);
+ g_clear_object (&self->target);
+}
+
+void
+gsk_vulkan_render_free (GskVulkanRender *self)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ VkDevice device;
+ guint i;
+
+ gsk_vulkan_render_cleanup (self);
+
+ device = gdk_vulkan_context_get_device (self->vulkan);
+
+ g_hash_table_iter_init (&iter, self->framebuffers);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ HashFramebufferEntry *fb = value;
+
+ vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
+ fb->framebuffer,
+ NULL);
+ g_slice_free (HashFramebufferEntry, fb);
+ g_object_weak_unref (G_OBJECT (key), gsk_vulkan_render_remove_framebuffer_from_image, self);
+ g_hash_table_iter_remove (&iter);
+ }
+ g_hash_table_unref (self->framebuffers);
+
+ for (i = 0; i < GSK_VULKAN_N_PIPELINES; i++)
+ g_clear_object (&self->pipelines[i]);
+
+ g_clear_pointer (&self->uploader, gsk_vulkan_uploader_free);
+
+ for (i = 0; i < 3; i++)
+ vkDestroyPipelineLayout (device,
+ self->pipeline_layout[i],
+ NULL);
+
+ vkDestroyRenderPass (device,
+ self->render_pass,
+ NULL);
+
+ vkDestroyDescriptorPool (device,
+ self->descriptor_pool,
+ NULL);
+ g_free (self->descriptor_sets);
+ g_hash_table_unref (self->descriptor_set_indexes);
+
+ vkDestroyDescriptorSetLayout (device,
+ self->descriptor_set_layout,
+ NULL);
+
+ vkDestroyFence (device,
+ self->fence,
+ NULL);
+
+ vkDestroySampler (device,
+ self->sampler,
+ NULL);
+
+ vkDestroySampler (device,
+ self->repeating_sampler,
+ NULL);
+
+ gsk_vulkan_command_pool_free (self->command_pool);
+
+ g_slice_free (GskVulkanRender, self);
+}
+
+gboolean
+gsk_vulkan_render_is_busy (GskVulkanRender *self)
+{
+ return vkGetFenceStatus (gdk_vulkan_context_get_device (self->vulkan), self->fence) != VK_SUCCESS;
+}
+
+void
+gsk_vulkan_render_reset (GskVulkanRender *self,
+ GskVulkanImage *target,
+ const graphene_rect_t *rect)
+{
+ gsk_vulkan_render_cleanup (self);
+
+ gsk_vulkan_render_setup (self, target, rect);
+}
+
+GskRenderer *
+gsk_vulkan_render_get_renderer (GskVulkanRender *self)
+{
+ return self->renderer;
+}
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanrendererprivate.h"
+
+#include "gskdebugprivate.h"
+#include "gskprivate.h"
+#include "gskrendererprivate.h"
+#include "gskrendernodeprivate.h"
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkanimageprivate.h"
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrenderprivate.h"
+#include "gskvulkanglyphcacheprivate.h"
+
+#include "gdk/gdktextureprivate.h"
+
+#include <graphene.h>
+
+typedef struct _GskVulkanTextureData GskVulkanTextureData;
+
+struct _GskVulkanTextureData {
+ GdkTexture *texture;
+ GskVulkanImage *image;
+ GskVulkanRenderer *renderer;
+};
+
+#ifdef G_ENABLE_DEBUG
+typedef struct {
+ GQuark frames;
+ GQuark render_passes;
+ GQuark fallback_pixels;
+ GQuark texture_pixels;
+} ProfileCounters;
+
+typedef struct {
+ GQuark cpu_time;
+ GQuark gpu_time;
+} ProfileTimers;
+#endif
+
+struct _GskVulkanRenderer
+{
+ GskRenderer parent_instance;
+
+ GdkVulkanContext *vulkan;
+
+ guint n_targets;
+ GskVulkanImage **targets;
+
+ GskVulkanRender *render;
+
+ GSList *textures;
+
+ GskVulkanGlyphCache *glyph_cache;
+
+#ifdef G_ENABLE_DEBUG
+ ProfileCounters profile_counters;
+ ProfileTimers profile_timers;
+#endif
+};
+
+struct _GskVulkanRendererClass
+{
+ GskRendererClass parent_class;
+};
+
+G_DEFINE_TYPE (GskVulkanRenderer, gsk_vulkan_renderer, GSK_TYPE_RENDERER)
+
+static void
+gsk_vulkan_renderer_free_targets (GskVulkanRenderer *self)
+{
+ guint i;
+
+ for (i = 0; i < self->n_targets; i++)
+ {
+ g_object_unref (self->targets[i]);
+ }
+
+ g_clear_pointer (&self->targets, g_free);
+ self->n_targets = 0;
+}
+
+static void
+gsk_vulkan_renderer_update_images_cb (GdkVulkanContext *context,
+ GskVulkanRenderer *self)
+{
+ GdkWindow *window;
+ gint scale_factor;
+ gsize width, height;
+ guint i;
+
+ gsk_vulkan_renderer_free_targets (self);
+
+ self->n_targets = gdk_vulkan_context_get_n_images (context);
+ self->targets = g_new (GskVulkanImage *, self->n_targets);
+
+ window = gsk_renderer_get_window (GSK_RENDERER (self));
+ scale_factor = gdk_window_get_scale_factor (window);
+ width = gdk_window_get_width (window) * scale_factor;
+ height = gdk_window_get_height (window) * scale_factor;
+
+ for (i = 0; i < self->n_targets; i++)
+ {
+ self->targets[i] = gsk_vulkan_image_new_for_swapchain (self->vulkan,
+ gdk_vulkan_context_get_image (context, i),
+ gdk_vulkan_context_get_image_format (self->vulkan),
+ width, height);
+ }
+}
+
+static gboolean
+gsk_vulkan_renderer_realize (GskRenderer *renderer,
+ GdkWindow *window,
+ GError **error)
+{
+ GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+
+ self->vulkan = gdk_window_create_vulkan_context (window, error);
+ if (self->vulkan == NULL)
+ return FALSE;
+
+ g_signal_connect (self->vulkan,
+ "images-updated",
+ G_CALLBACK (gsk_vulkan_renderer_update_images_cb),
+ self);
+ gsk_vulkan_renderer_update_images_cb (self->vulkan, self);
+
+ self->render = gsk_vulkan_render_new (renderer, self->vulkan);
+
+ self->glyph_cache = gsk_vulkan_glyph_cache_new (self->vulkan);
+
+ return TRUE;
+}
+
+static void
+gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
+{
+ GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+ GSList *l;
+
+ g_clear_object (&self->glyph_cache);
+
+ for (l = self->textures; l; l = l->next)
+ {
+ GskVulkanTextureData *data = l->data;
+
+ data->renderer = NULL;
+ gdk_texture_clear_render_data (data->texture);
+ }
+ g_clear_pointer (&self->textures, (GDestroyNotify) g_slist_free);
+
+ g_clear_pointer (&self->render, gsk_vulkan_render_free);
+
+ gsk_vulkan_renderer_free_targets (self);
+ g_signal_handlers_disconnect_by_func(self->vulkan,
+ gsk_vulkan_renderer_update_images_cb,
+ self);
+
+ g_clear_object (&self->vulkan);
+}
+
+static GdkTexture *
+gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
+ GskRenderNode *root,
+ const graphene_rect_t *viewport)
+{
+ GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+ GskVulkanRender *render;
+ GskVulkanImage *image;
+ GdkTexture *texture;
+#ifdef G_ENABLE_DEBUG
+ GskProfiler *profiler;
+ gint64 cpu_time;
+#endif
+
+#ifdef G_ENABLE_DEBUG
+ profiler = gsk_renderer_get_profiler (renderer);
+ gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
+ gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
+ gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
+ gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
+#endif
+
+ render = gsk_vulkan_render_new (renderer, self->vulkan);
+
+ image = gsk_vulkan_image_new_for_framebuffer (self->vulkan,
+ ceil (viewport->size.width),
+ ceil (viewport->size.height));
+
+ gsk_vulkan_render_reset (render, image, viewport);
+
+ gsk_vulkan_render_add_node (render, root);
+
+ gsk_vulkan_render_upload (render);
+
+ gsk_vulkan_render_draw (render);
+
+ texture = gsk_vulkan_render_download_target (render);
+
+ g_object_unref (image);
+ gsk_vulkan_render_free (render);
+
+#ifdef G_ENABLE_DEBUG
+ cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
+ gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
+
+ gsk_profiler_push_samples (profiler);
+#endif
+
+ return texture;
+}
+
+static void
+gsk_vulkan_renderer_render (GskRenderer *renderer,
+ GskRenderNode *root)
+{
+ GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+ GskVulkanRender *render;
+#ifdef G_ENABLE_DEBUG
+ GskProfiler *profiler;
+ gint64 cpu_time;
+#endif
+
+#ifdef G_ENABLE_DEBUG
+ profiler = gsk_renderer_get_profiler (renderer);
+ gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
+ gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
+ gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
+ gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
+#endif
+
+ render = self->render;
+
+ gsk_vulkan_render_reset (render, self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)], NULL);
+
+ gsk_vulkan_render_add_node (render, root);
+
+ gsk_vulkan_render_upload (render);
+
+ gsk_vulkan_render_draw (render);
+
+#ifdef G_ENABLE_DEBUG
+ gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
+
+ cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
+ gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
+
+ gsk_profiler_push_samples (profiler);
+#endif
+}
+
+static GdkDrawingContext *
+gsk_vulkan_renderer_begin_draw_frame (GskRenderer *renderer,
+ const cairo_region_t *region)
+{
+ GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+ GdkDrawingContext *result;
+
+ result = gdk_window_begin_draw_frame (gsk_renderer_get_window (renderer),
+ GDK_DRAW_CONTEXT (self->vulkan),
+ region);
+
+ return result;
+}
+
+static void
+gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass)
+{
+ GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
+
+ renderer_class->realize = gsk_vulkan_renderer_realize;
+ renderer_class->unrealize = gsk_vulkan_renderer_unrealize;
+ renderer_class->render = gsk_vulkan_renderer_render;
+ renderer_class->render_texture = gsk_vulkan_renderer_render_texture;
+ renderer_class->begin_draw_frame = gsk_vulkan_renderer_begin_draw_frame;
+}
+
+static void
+gsk_vulkan_renderer_init (GskVulkanRenderer *self)
+{
+#ifdef G_ENABLE_DEBUG
+ GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
+#endif
+
+ gsk_ensure_resources ();
+
+#ifdef G_ENABLE_DEBUG
+ self->profile_counters.frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE);
+ self->profile_counters.render_passes = gsk_profiler_add_counter (profiler, "render-passes", "Render passes", FALSE);
+ self->profile_counters.fallback_pixels = gsk_profiler_add_counter (profiler, "fallback-pixels", "Fallback pixels", TRUE);
+ self->profile_counters.texture_pixels = gsk_profiler_add_counter (profiler, "texture-pixels", "Texture pixels", TRUE);
+
+ self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
+ if (GSK_RENDER_MODE_CHECK (SYNC))
+ self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
+#endif
+}
+
+static void
+gsk_vulkan_renderer_clear_texture (gpointer p)
+{
+ GskVulkanTextureData *data = p;
+
+ if (data->renderer != NULL)
+ data->renderer->textures = g_slist_remove (data->renderer->textures, data);
+
+ g_object_unref (data->image);
+
+ g_slice_free (GskVulkanTextureData, data);
+}
+
+GskVulkanImage *
+gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
+ GdkTexture *texture,
+ GskVulkanUploader *uploader)
+{
+ GskVulkanTextureData *data;
+ cairo_surface_t *surface;
+ GskVulkanImage *image;
+
+ data = gdk_texture_get_render_data (texture, self);
+ if (data)
+ return g_object_ref (data->image);
+
+ surface = gdk_texture_download_surface (texture);
+ image = gsk_vulkan_image_new_from_data (uploader,
+ cairo_image_surface_get_data (surface),
+ cairo_image_surface_get_width (surface),
+ cairo_image_surface_get_height (surface),
+ cairo_image_surface_get_stride (surface));
+ cairo_surface_destroy (surface);
+
+ data = g_slice_new0 (GskVulkanTextureData);
+ data->image = image;
+ data->texture = texture;
+ data->renderer = self;
+
+ if (gdk_texture_set_render_data (texture, self, data, gsk_vulkan_renderer_clear_texture))
+ {
+ g_object_ref (data->image);
+ self->textures = g_slist_prepend (self->textures, data);
+ }
+ else
+ {
+ g_slice_free (GskVulkanTextureData, data);
+ }
+
+ return image;
+}
+
+guint
+gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
+ PangoFont *font,
+ PangoGlyph glyph,
+ float scale)
+{
+ return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, scale)->texture_index;
+}
+
+GskVulkanImage *
+gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
+ GskVulkanUploader *uploader,
+ guint index)
+{
+ return g_object_ref (gsk_vulkan_glyph_cache_get_glyph_image (self->glyph_cache, uploader, index));
+}
+
+GskVulkanCachedGlyph *
+gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
+ PangoFont *font,
+ PangoGlyph glyph,
+ float scale)
+{
+ return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, scale);
+}
--- /dev/null
+#ifndef __GSK_VULKAN_RENDERER_PRIVATE_H__
+#define __GSK_VULKAN_RENDERER_PRIVATE_H__
+
+#include <vulkan/vulkan.h>
+#include <gsk/gskrenderer.h>
+
+#include "gskvulkanimageprivate.h"
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_VULKAN_RENDERER (gsk_vulkan_renderer_get_type ())
+
+#define GSK_VULKAN_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRenderer))
+#define GSK_IS_VULKAN_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_VULKAN_RENDERER))
+#define GSK_VULKAN_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
+#define GSK_IS_VULKAN_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_VULKAN_RENDERER))
+#define GSK_VULKAN_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_VULKAN_RENDERER, GskVulkanRendererClass))
+
+typedef struct _GskVulkanRenderer GskVulkanRenderer;
+typedef struct _GskVulkanRendererClass GskVulkanRendererClass;
+
+GType gsk_vulkan_renderer_get_type (void) G_GNUC_CONST;
+
+GskVulkanImage * gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
+ GdkTexture *texture,
+ GskVulkanUploader *uploader);
+
+typedef struct
+{
+ guint texture_index;
+
+ float tx;
+ float ty;
+ float tw;
+ float th;
+
+ int draw_x;
+ int draw_y;
+ int draw_width;
+ int draw_height;
+
+ guint64 timestamp;
+} GskVulkanCachedGlyph;
+
+guint gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *renderer,
+ PangoFont *font,
+ PangoGlyph glyph,
+ float scale);
+
+GskVulkanImage * gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
+ GskVulkanUploader *uploader,
+ guint index);
+
+GskVulkanCachedGlyph * gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
+ PangoFont *font,
+ PangoGlyph glyph,
+ float scale);
+
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_RENDERER_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanrenderpassprivate.h"
+
+#include "gskdebugprivate.h"
+#include "gskprofilerprivate.h"
+#include "gskrendernodeprivate.h"
+#include "gskrenderer.h"
+#include "gskrendererprivate.h"
+#include "gskroundedrectprivate.h"
+#include "gskvulkanblendmodepipelineprivate.h"
+#include "gskvulkanblurpipelineprivate.h"
+#include "gskvulkanborderpipelineprivate.h"
+#include "gskvulkanboxshadowpipelineprivate.h"
+#include "gskvulkanclipprivate.h"
+#include "gskvulkancolorpipelineprivate.h"
+#include "gskvulkancolortextpipelineprivate.h"
+#include "gskvulkancrossfadepipelineprivate.h"
+#include "gskvulkaneffectpipelineprivate.h"
+#include "gskvulkanlineargradientpipelineprivate.h"
+#include "gskvulkantextpipelineprivate.h"
+#include "gskvulkantexturepipelineprivate.h"
+#include "gskvulkanimageprivate.h"
+#include "gskvulkanpushconstantsprivate.h"
+#include "gskvulkanrendererprivate.h"
+#include "gskprivate.h"
+
+#include <cairo-ft.h>
+
+#define ORTHO_NEAR_PLANE -10000
+#define ORTHO_FAR_PLANE 10000
+
+typedef union _GskVulkanOp GskVulkanOp;
+typedef struct _GskVulkanOpRender GskVulkanOpRender;
+typedef struct _GskVulkanOpText GskVulkanOpText;
+typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants;
+
+typedef enum {
+ /* GskVulkanOpRender */
+ GSK_VULKAN_OP_FALLBACK,
+ GSK_VULKAN_OP_FALLBACK_CLIP,
+ GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP,
+ GSK_VULKAN_OP_SURFACE,
+ GSK_VULKAN_OP_TEXTURE,
+ GSK_VULKAN_OP_COLOR,
+ GSK_VULKAN_OP_LINEAR_GRADIENT,
+ GSK_VULKAN_OP_OPACITY,
+ GSK_VULKAN_OP_BLUR,
+ GSK_VULKAN_OP_COLOR_MATRIX,
+ GSK_VULKAN_OP_BORDER,
+ GSK_VULKAN_OP_INSET_SHADOW,
+ GSK_VULKAN_OP_OUTSET_SHADOW,
+ GSK_VULKAN_OP_REPEAT,
+ GSK_VULKAN_OP_CROSS_FADE,
+ GSK_VULKAN_OP_BLEND_MODE,
+ /* GskVulkanOpText */
+ GSK_VULKAN_OP_TEXT,
+ GSK_VULKAN_OP_COLOR_TEXT,
+ /* GskVulkanOpPushConstants */
+ GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS,
+} GskVulkanOpType;
+
+/* render ops with 0, 1 or 2 sources */
+struct _GskVulkanOpRender
+{
+ GskVulkanOpType type;
+ GskRenderNode *node; /* node that's the source of this op */
+ GskVulkanPipeline *pipeline; /* pipeline to use */
+ GskRoundedRect clip; /* clip rect (or random memory if not relevant) */
+ GskVulkanImage *source; /* source image to render */
+ GskVulkanImage *source2; /* second source image to render (if relevant) */
+ gsize vertex_offset; /* offset into vertex buffer */
+ gsize vertex_count; /* number of vertices */
+ gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
+ gsize descriptor_set_index2; /* descriptor index for the second source (if relevant) */
+ graphene_rect_t source_rect; /* area that source maps to */
+ graphene_rect_t source2_rect; /* area that source2 maps to */
+};
+
+struct _GskVulkanOpText
+{
+ GskVulkanOpType type;
+ GskRenderNode *node; /* node that's the source of this op */
+ GskVulkanPipeline *pipeline; /* pipeline to use */
+ GskRoundedRect clip; /* clip rect (or random memory if not relevant) */
+ GskVulkanImage *source; /* source image to render */
+ gsize vertex_offset; /* offset into vertex buffer */
+ gsize vertex_count; /* number of vertices */
+ gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
+ guint texture_index; /* index of the texture in the glyph cache */
+ guint start_glyph; /* the first glyph in nodes glyphstring that we render */
+ guint num_glyphs; /* number of *non-empty* glyphs (== instances) we render */
+ float scale;
+};
+
+struct _GskVulkanOpPushConstants
+{
+ GskVulkanOpType type;
+ GskRenderNode *node; /* node that's the source of this op */
+ GskVulkanPushConstants constants; /* new constants to push */
+};
+
+union _GskVulkanOp
+{
+ GskVulkanOpType type;
+ GskVulkanOpRender render;
+ GskVulkanOpText text;
+ GskVulkanOpPushConstants constants;
+};
+
+struct _GskVulkanRenderPass
+{
+ GdkVulkanContext *vulkan;
+
+ GArray *render_ops;
+
+ GskVulkanImage *target;
+ int scale_factor;
+ graphene_rect_t viewport;
+ cairo_region_t *clip;
+ graphene_matrix_t mv;
+ graphene_matrix_t p;
+
+ VkRenderPass render_pass;
+ VkSemaphore signal_semaphore;
+ GArray *wait_semaphores;
+ GskVulkanBuffer *vertex_data;
+
+ GQuark fallback_pixels;
+ GQuark texture_pixels;
+};
+
+GskVulkanRenderPass *
+gsk_vulkan_render_pass_new (GdkVulkanContext *context,
+ GskVulkanImage *target,
+ int scale_factor,
+ graphene_matrix_t *mv,
+ graphene_rect_t *viewport,
+ cairo_region_t *clip,
+ VkSemaphore signal_semaphore)
+{
+ GskVulkanRenderPass *self;
+ VkImageLayout final_layout;
+
+ self = g_slice_new0 (GskVulkanRenderPass);
+ self->vulkan = g_object_ref (context);
+ self->render_ops = g_array_new (FALSE, FALSE, sizeof (GskVulkanOp));
+
+ self->target = g_object_ref (target);
+ self->scale_factor = scale_factor;
+ self->clip = cairo_region_copy (clip);
+ self->viewport = *viewport;
+
+ self->mv = *mv;
+ graphene_matrix_init_ortho (&self->p,
+ viewport->origin.x, viewport->origin.x + viewport->size.width,
+ viewport->origin.y, viewport->origin.y + viewport->size.height,
+ ORTHO_NEAR_PLANE,
+ ORTHO_FAR_PLANE);
+
+ if (signal_semaphore != VK_NULL_HANDLE) // this is a dependent pass
+ final_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ else
+ final_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
+ &(VkRenderPassCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+ .attachmentCount = 1,
+ .pAttachments = (VkAttachmentDescription[]) {
+ {
+ .format = gdk_vulkan_context_get_image_format (self->vulkan),
+ .samples = VK_SAMPLE_COUNT_1_BIT,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+ .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .finalLayout = final_layout
+ }
+ },
+ .subpassCount = 1,
+ .pSubpasses = (VkSubpassDescription []) {
+ {
+ .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+ .inputAttachmentCount = 0,
+ .colorAttachmentCount = 1,
+ .pColorAttachments = (VkAttachmentReference []) {
+ {
+ .attachment = 0,
+ .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ }
+ },
+ .pResolveAttachments = (VkAttachmentReference []) {
+ {
+ .attachment = VK_ATTACHMENT_UNUSED,
+ .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ }
+ },
+ .pDepthStencilAttachment = NULL,
+ }
+ },
+ .dependencyCount = 0
+ },
+ NULL,
+ &self->render_pass);
+
+ self->signal_semaphore = signal_semaphore;
+ self->wait_semaphores = g_array_new (FALSE, FALSE, sizeof (VkSemaphore));
+ self->vertex_data = NULL;
+
+#ifdef G_ENABLE_DEBUG
+ self->fallback_pixels = g_quark_from_static_string ("fallback-pixels");
+ self->texture_pixels = g_quark_from_static_string ("texture-pixels");
+#endif
+
+ return self;
+}
+
+void
+gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
+{
+ g_array_unref (self->render_ops);
+ g_object_unref (self->vulkan);
+ g_object_unref (self->target);
+ cairo_region_destroy (self->clip);
+ vkDestroyRenderPass (gdk_vulkan_context_get_device (self->vulkan),
+ self->render_pass,
+ NULL);
+ if (self->vertex_data)
+ gsk_vulkan_buffer_free (self->vertex_data);
+ if (self->signal_semaphore != VK_NULL_HANDLE)
+ vkDestroySemaphore (gdk_vulkan_context_get_device (self->vulkan),
+ self->signal_semaphore,
+ NULL);
+ g_array_unref (self->wait_semaphores);
+
+
+ g_slice_free (GskVulkanRenderPass, self);
+}
+
+static gboolean
+font_has_color_glyphs (const PangoFont *font)
+{
+ cairo_scaled_font_t *scaled_font;
+ gboolean has_color = FALSE;
+
+ scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
+ if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT)
+ {
+ FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+ has_color = (FT_HAS_COLOR (ft_face) != 0);
+ cairo_ft_scaled_font_unlock_face (scaled_font);
+ }
+
+ return has_color;
+}
+
+#define FALLBACK(...) G_STMT_START { \
+ GSK_NOTE (FALLBACK, g_print (__VA_ARGS__)); \
+ goto fallback; \
+}G_STMT_END
+
+static void
+gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ const GskVulkanPushConstants *constants,
+ GskRenderNode *node)
+{
+ GskVulkanOp op = {
+ .type = GSK_VULKAN_OP_FALLBACK,
+ .render.node = node
+ };
+ GskVulkanPipelineType pipeline_type;
+
+ switch (gsk_render_node_get_node_type (node))
+ {
+ case GSK_NOT_A_RENDER_NODE:
+ g_assert_not_reached ();
+ return;
+ case GSK_SHADOW_NODE:
+ default:
+ FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name);
+
+ case GSK_REPEAT_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
+ else
+ FALLBACK ("Repeat nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_REPEAT;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_BLEND_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED;
+ else
+ FALLBACK ("Blend nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_BLEND_MODE;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_CROSS_FADE_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED;
+ else
+ FALLBACK ("Cross fade nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_CROSS_FADE;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_INSET_SHADOW_NODE:
+ if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
+ FALLBACK ("Blur support not implemented for inset shadows\n");
+ else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED;
+ else
+ FALLBACK ("Inset shadow nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_INSET_SHADOW;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_OUTSET_SHADOW_NODE:
+ if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
+ FALLBACK ("Blur support not implemented for outset shadows\n");
+ else if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED;
+ else
+ FALLBACK ("Outset shadow nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_OUTSET_SHADOW;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_CAIRO_NODE:
+ if (gsk_cairo_node_peek_surface (node) == NULL)
+ return;
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
+ else
+ FALLBACK ("Cairo nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_SURFACE;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_TEXT_NODE:
+ {
+ const PangoFont *font = gsk_text_node_peek_font (node);
+ const PangoGlyphInfo *glyphs = gsk_text_node_peek_glyphs (node);
+ guint num_glyphs = gsk_text_node_get_num_glyphs (node);
+ int i;
+ guint count;
+ guint texture_index;
+ GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render));
+
+ if (font_has_color_glyphs (font))
+ {
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED;
+ else
+ FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_COLOR_TEXT;
+ }
+ else
+ {
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXT;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
+ else
+ FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_TEXT;
+ }
+ op.text.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+
+ op.text.start_glyph = 0;
+ op.text.texture_index = G_MAXUINT;
+ op.text.scale = self->scale_factor;
+
+ for (i = 0, count = 0; i < num_glyphs; i++)
+ {
+ const PangoGlyphInfo *gi = &glyphs[i];
+
+ texture_index = gsk_vulkan_renderer_cache_glyph (renderer, (PangoFont *)font, gi->glyph, op.text.scale);
+ if (op.text.texture_index == G_MAXUINT)
+ op.text.texture_index = texture_index;
+ if (texture_index != op.text.texture_index)
+ {
+ op.text.num_glyphs = count;
+
+ g_array_append_val (self->render_ops, op);
+
+ count = 1;
+ op.text.start_glyph = i;
+ op.text.texture_index = texture_index;
+ }
+ else
+ count++;
+ }
+
+ if (op.text.texture_index != G_MAXUINT && count != 0)
+ {
+ op.text.num_glyphs = count;
+ g_array_append_val (self->render_ops, op);
+ }
+
+ return;
+ }
+
+ case GSK_TEXTURE_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
+ else
+ FALLBACK ("Texture nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_TEXTURE;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_COLOR_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED;
+ else
+ FALLBACK ("Color nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_COLOR;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_LINEAR_GRADIENT_NODE:
+ case GSK_REPEATING_LINEAR_GRADIENT_NODE:
+ if (gsk_linear_gradient_node_get_n_color_stops (node) > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS)
+ FALLBACK ("Linear gradient with %zu color stops, hardcoded limit is %u\n",
+ gsk_linear_gradient_node_get_n_color_stops (node),
+ GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS);
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED;
+ else
+ FALLBACK ("Linear gradient nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_LINEAR_GRADIENT;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_OPACITY_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
+ else
+ FALLBACK ("Opacity nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_OPACITY;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_BLUR_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_BLUR;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED;
+ else
+ FALLBACK ("Blur nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_BLUR;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_COLOR_MATRIX_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
+ else
+ FALLBACK ("Color matrix nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_COLOR_MATRIX;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_BORDER_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_BORDER;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED;
+ else
+ FALLBACK ("Border nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_BORDER;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
+ case GSK_CONTAINER_NODE:
+ {
+ guint i;
+
+ for (i = 0; i < gsk_container_node_get_n_children (node); i++)
+ {
+ gsk_vulkan_render_pass_add_node (self, render, constants, gsk_container_node_get_child (node, i));
+ }
+ }
+ return;
+
+ case GSK_TRANSFORM_NODE:
+ {
+ graphene_matrix_t transform, mv;
+ GskRenderNode *child;
+
+#if 0
+ if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
+ FALLBACK ("Transform nodes can't deal with clip type %u\n", clip->type);
+#endif
+
+ graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
+ graphene_matrix_init_from_matrix (&mv, &self->mv);
+ graphene_matrix_multiply (&transform, &mv, &self->mv);
+ child = gsk_transform_node_get_child (node);
+ if (!gsk_vulkan_push_constants_transform (&op.constants.constants, constants, &transform, &child->bounds))
+ FALLBACK ("Transform nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
+ g_array_append_val (self->render_ops, op);
+
+ gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, child);
+ gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
+ graphene_matrix_init_from_matrix (&self->mv, &mv);
+ g_array_append_val (self->render_ops, op);
+ }
+ return;
+
+ case GSK_CLIP_NODE:
+ {
+ if (!gsk_vulkan_push_constants_intersect_rect (&op.constants.constants, constants, gsk_clip_node_peek_clip (node)))
+ FALLBACK ("Failed to find intersection between clip of type %u and rectangle\n", constants->clip.type);
+ if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
+ return;
+
+ op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
+ g_array_append_val (self->render_ops, op);
+
+ gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_clip_node_get_child (node));
+
+ gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
+ g_array_append_val (self->render_ops, op);
+ }
+ return;
+
+ case GSK_ROUNDED_CLIP_NODE:
+ {
+ if (!gsk_vulkan_push_constants_intersect_rounded (&op.constants.constants,
+ constants,
+ gsk_rounded_clip_node_peek_clip (node)))
+ FALLBACK ("Failed to find intersection between clip of type %u and rounded rectangle\n", constants->clip.type);
+ if (op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
+ return;
+
+ op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
+ g_array_append_val (self->render_ops, op);
+
+ gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_rounded_clip_node_get_child (node));
+
+ gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
+ g_array_append_val (self->render_ops, op);
+ }
+ return;
+ }
+
+ g_assert_not_reached ();
+ return;
+
+fallback:
+ switch (constants->clip.type)
+ {
+ case GSK_VULKAN_CLIP_NONE:
+ op.type = GSK_VULKAN_OP_FALLBACK;
+ break;
+ case GSK_VULKAN_CLIP_RECT:
+ op.type = GSK_VULKAN_OP_FALLBACK_CLIP;
+ gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
+ break;
+ case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
+ case GSK_VULKAN_CLIP_ROUNDED:
+ op.type = GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP;
+ gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
+ break;
+ case GSK_VULKAN_CLIP_ALL_CLIPPED:
+ default:
+ g_assert_not_reached ();
+ return;
+ }
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_TEXTURE);
+ g_array_append_val (self->render_ops, op);
+}
+#undef FALLBACK
+
+void
+gsk_vulkan_render_pass_add (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ GskRenderNode *node)
+{
+ GskVulkanOp op = { 0, };
+ graphene_matrix_t mvp;
+
+ graphene_matrix_multiply (&self->mv, &self->p, &mvp);
+ op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
+ gsk_vulkan_push_constants_init (&op.constants.constants, &mvp, &self->viewport);
+ g_array_append_val (self->render_ops, op);
+
+ gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, node);
+}
+
+static GskVulkanImage *
+gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ GskVulkanUploader *uploader,
+ GskRenderNode *node,
+ const graphene_rect_t *bounds,
+ GskVulkanClip *current_clip,
+ graphene_rect_t *tex_rect)
+{
+ GskVulkanImage *result;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ switch ((guint) gsk_render_node_get_node_type (node))
+ {
+ case GSK_TEXTURE_NODE:
+ if (graphene_rect_equal (bounds, &node->bounds))
+ {
+ result = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+ gsk_texture_node_get_texture (node),
+ uploader);
+ gsk_vulkan_render_add_cleanup_image (render, result);
+ *tex_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
+ return result;
+ }
+ break;
+
+ case GSK_CAIRO_NODE:
+ if (graphene_rect_equal (bounds, &node->bounds))
+ {
+ surface = cairo_surface_reference ((cairo_surface_t *)gsk_cairo_node_peek_surface (node));
+ goto got_surface;
+ }
+ break;
+
+ default:
+ {
+ VkSemaphore semaphore;
+ graphene_rect_t view;
+ cairo_region_t *clip;
+ GskVulkanRenderPass *pass;
+ graphene_rect_t clipped;
+
+ if (current_clip)
+ graphene_rect_intersection (¤t_clip->rect.bounds, bounds, &clipped);
+ else
+ clipped = *bounds;
+
+ if (clipped.size.width == 0 || clipped.size.height == 0)
+ return NULL;
+
+ graphene_matrix_transform_bounds (&self->mv, &clipped, &view);
+ view.origin.x = floor (view.origin.x);
+ view.origin.y = floor (view.origin.y);
+ view.size.width = ceil (view.size.width);
+ view.size.height = ceil (view.size.height);
+
+ result = gsk_vulkan_image_new_for_texture (self->vulkan,
+ view.size.width,
+ view.size.height);
+
+#ifdef G_ENABLE_DEBUG
+ {
+ GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
+ gsk_profiler_counter_add (profiler,
+ self->texture_pixels,
+ view.size.width * view.size.height);
+ }
+#endif
+
+ vkCreateSemaphore (gdk_vulkan_context_get_device (self->vulkan),
+ &(VkSemaphoreCreateInfo) {
+ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+ NULL,
+ 0
+ },
+ NULL,
+ &semaphore);
+
+ g_array_append_val (self->wait_semaphores, semaphore);
+
+ clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
+ 0, 0,
+ gsk_vulkan_image_get_width (result),
+ gsk_vulkan_image_get_height (result)
+ });
+
+ pass = gsk_vulkan_render_pass_new (self->vulkan,
+ result,
+ self->scale_factor,
+ &self->mv,
+ &view,
+ clip,
+ semaphore);
+
+ cairo_region_destroy (clip);
+
+ gsk_vulkan_render_add_render_pass (render, pass);
+ gsk_vulkan_render_pass_add (pass, render, node);
+ gsk_vulkan_render_add_cleanup_image (render, result);
+
+ /* assuming the unclipped bounds should go to texture coordinates 0..1,
+ * calculate the coordinates for the clipped texture size
+ */
+ tex_rect->origin.x = (bounds->origin.x - clipped.origin.x)/clipped.size.width;
+ tex_rect->origin.y = (bounds->origin.y - clipped.origin.y)/clipped.size.height;
+ tex_rect->size.width = bounds->size.width/clipped.size.width;
+ tex_rect->size.height = bounds->size.height/clipped.size.height;
+
+ return result;
+ }
+ }
+
+ GSK_NOTE (FALLBACK, g_print ("Node as texture not implemented for this case. Using %gx%g fallback surface\n",
+ ceil (bounds->size.width),
+ ceil (bounds->size.height)));
+#ifdef G_ENABLE_DEBUG
+ {
+ GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
+ gsk_profiler_counter_add (profiler,
+ self->fallback_pixels,
+ ceil (bounds->size.width) * ceil (bounds->size.height));
+ }
+#endif
+
+ /* XXX: We could intersect bounds with clip bounds here */
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ ceil (bounds->size.width),
+ ceil (bounds->size.height));
+ cr = cairo_create (surface);
+ cairo_translate (cr, -bounds->origin.x, -bounds->origin.y);
+
+ gsk_render_node_draw (node, cr);
+
+ cairo_destroy (cr);
+
+got_surface:
+ result = gsk_vulkan_image_new_from_data (uploader,
+ cairo_image_surface_get_data (surface),
+ cairo_image_surface_get_width (surface),
+ cairo_image_surface_get_height (surface),
+ cairo_image_surface_get_stride (surface));
+
+ cairo_surface_destroy (surface);
+
+ gsk_vulkan_render_add_cleanup_image (render, result);
+
+ tex_rect->origin.x = (node->bounds.origin.x - bounds->origin.x)/bounds->size.width;
+ tex_rect->origin.y = (node->bounds.origin.y - bounds->origin.y)/bounds->size.height;
+ tex_rect->size.width = node->bounds.size.width/bounds->size.width;
+ tex_rect->size.height = node->bounds.size.height/bounds->size.height;
+
+ return result;
+}
+
+static void
+gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self,
+ GskVulkanOpRender *op,
+ GskVulkanRender *render,
+ GskVulkanUploader *uploader)
+{
+ GskRenderNode *node;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ node = op->node;
+
+ GSK_NOTE (FALLBACK,
+ g_print ("Upload op=%s, node %s[%p], bounds %gx%g\n",
+ op->type == GSK_VULKAN_OP_FALLBACK_CLIP ? "fallback-clip" :
+ (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP ? "fallback-rounded-clip" : "fallback"),
+ node->name ? node->name : node->node_class->type_name, node,
+ ceil (node->bounds.size.width),
+ ceil (node->bounds.size.height)));
+#ifdef G_ENABLE_DEBUG
+ {
+ GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
+ gsk_profiler_counter_add (profiler,
+ self->fallback_pixels,
+ ceil (node->bounds.size.width) * ceil (node->bounds.size.height));
+ }
+#endif
+
+ /* XXX: We could intersect bounds with clip bounds here */
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ ceil (node->bounds.size.width * self->scale_factor),
+ ceil (node->bounds.size.height * self->scale_factor));
+ cairo_surface_set_device_scale (surface, self->scale_factor, self->scale_factor);
+ cr = cairo_create (surface);
+ cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
+
+ if (op->type == GSK_VULKAN_OP_FALLBACK_CLIP)
+ {
+ cairo_rectangle (cr,
+ op->clip.bounds.origin.x, op->clip.bounds.origin.y,
+ op->clip.bounds.size.width, op->clip.bounds.size.height);
+ cairo_clip (cr);
+ }
+ else if (op->type == GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP)
+ {
+ gsk_rounded_rect_path (&op->clip, cr);
+ cairo_clip (cr);
+ }
+ else
+ {
+ g_assert (op->type == GSK_VULKAN_OP_FALLBACK);
+ }
+
+ gsk_render_node_draw (node, cr);
+
+ cairo_destroy (cr);
+
+ op->source = gsk_vulkan_image_new_from_data (uploader,
+ cairo_image_surface_get_data (surface),
+ cairo_image_surface_get_width (surface),
+ cairo_image_surface_get_height (surface),
+ cairo_image_surface_get_stride (surface));
+
+ op->source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
+
+ cairo_surface_destroy (surface);
+
+ gsk_vulkan_render_add_cleanup_image (render, op->source);
+}
+
+void
+gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ GskVulkanUploader *uploader)
+{
+ GskVulkanOp *op;
+ guint i;
+ GskVulkanClip *clip = NULL;
+
+ for (i = 0; i < self->render_ops->len; i++)
+ {
+ op = &g_array_index (self->render_ops, GskVulkanOp, i);
+
+ switch (op->type)
+ {
+ case GSK_VULKAN_OP_FALLBACK:
+ case GSK_VULKAN_OP_FALLBACK_CLIP:
+ case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+ gsk_vulkan_render_pass_upload_fallback (self, &op->render, render, uploader);
+ break;
+
+ case GSK_VULKAN_OP_SURFACE:
+ {
+ cairo_surface_t *surface;
+
+ surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (op->render.node);
+ op->render.source = gsk_vulkan_image_new_from_data (uploader,
+ cairo_image_surface_get_data (surface),
+ cairo_image_surface_get_width (surface),
+ cairo_image_surface_get_height (surface),
+ cairo_image_surface_get_stride (surface));
+ op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
+
+ gsk_vulkan_render_add_cleanup_image (render, op->render.source);
+ }
+ break;
+
+ case GSK_VULKAN_OP_TEXT:
+ case GSK_VULKAN_OP_COLOR_TEXT:
+ {
+ op->text.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+ uploader,
+ op->text.texture_index);
+ gsk_vulkan_render_add_cleanup_image (render, op->text.source);
+ }
+ break;
+
+ case GSK_VULKAN_OP_TEXTURE:
+ {
+ op->render.source = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+ gsk_texture_node_get_texture (op->render.node),
+ uploader);
+ op->render.source_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
+ gsk_vulkan_render_add_cleanup_image (render, op->render.source);
+ }
+ break;
+
+ case GSK_VULKAN_OP_OPACITY:
+ {
+ GskRenderNode *child = gsk_opacity_node_get_child (op->render.node);
+
+ op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+ render,
+ uploader,
+ child,
+ &child->bounds,
+ clip,
+ &op->render.source_rect);
+ }
+ break;
+
+ case GSK_VULKAN_OP_REPEAT:
+ {
+ GskRenderNode *child = gsk_repeat_node_get_child (op->render.node);
+ const graphene_rect_t *bounds = &op->render.node->bounds;
+ const graphene_rect_t *child_bounds = gsk_repeat_node_peek_child_bounds (op->render.node);
+
+ op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+ render,
+ uploader,
+ child,
+ child_bounds,
+ NULL,
+ &op->render.source_rect);
+
+ op->render.source_rect.origin.x = (bounds->origin.x - child_bounds->origin.x)/child_bounds->size.width;
+ op->render.source_rect.origin.y = (bounds->origin.y - child_bounds->origin.y)/child_bounds->size.height;
+ op->render.source_rect.size.width = bounds->size.width / child_bounds->size.width;
+ op->render.source_rect.size.height = bounds->size.height / child_bounds->size.height;
+ }
+ break;
+
+ case GSK_VULKAN_OP_BLUR:
+ {
+ GskRenderNode *child = gsk_blur_node_get_child (op->render.node);
+
+ op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+ render,
+ uploader,
+ child,
+ &child->bounds,
+ clip,
+ &op->render.source_rect);
+ }
+ break;
+
+ case GSK_VULKAN_OP_COLOR_MATRIX:
+ {
+ GskRenderNode *child = gsk_color_matrix_node_get_child (op->render.node);
+
+ op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+ render,
+ uploader,
+ child,
+ &child->bounds,
+ clip,
+ &op->render.source_rect);
+ }
+ break;
+
+ case GSK_VULKAN_OP_CROSS_FADE:
+ {
+ GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->render.node);
+ GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->render.node);
+ const graphene_rect_t *bounds = &op->render.node->bounds;
+
+ op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+ render,
+ uploader,
+ start,
+ &start->bounds,
+ clip,
+ &op->render.source_rect);
+ op->render.source_rect.origin.x = (bounds->origin.x - start->bounds.origin.x)/start->bounds.size.width;
+ op->render.source_rect.origin.y = (bounds->origin.y - start->bounds.origin.y)/start->bounds.size.height;
+ op->render.source_rect.size.width = bounds->size.width / start->bounds.size.width;
+ op->render.source_rect.size.height = bounds->size.height / start->bounds.size.height;
+
+ op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
+ render,
+ uploader,
+ end,
+ &end->bounds,
+ clip,
+ &op->render.source2_rect);
+ op->render.source2_rect.origin.x = (bounds->origin.x - end->bounds.origin.x)/end->bounds.size.width;
+ op->render.source2_rect.origin.y = (bounds->origin.y - end->bounds.origin.y)/end->bounds.size.height;
+ op->render.source2_rect.size.width = bounds->size.width / end->bounds.size.width;
+ op->render.source2_rect.size.height = bounds->size.height / end->bounds.size.height;
+ }
+ break;
+
+ case GSK_VULKAN_OP_BLEND_MODE:
+ {
+ GskRenderNode *top = gsk_blend_node_get_top_child (op->render.node);
+ GskRenderNode *bottom = gsk_blend_node_get_bottom_child (op->render.node);
+ const graphene_rect_t *bounds = &op->render.node->bounds;
+
+ op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
+ render,
+ uploader,
+ top,
+ &top->bounds,
+ clip,
+ &op->render.source_rect);
+ op->render.source_rect.origin.x = (bounds->origin.x - top->bounds.origin.x)/top->bounds.size.width;
+ op->render.source_rect.origin.y = (bounds->origin.y - top->bounds.origin.y)/top->bounds.size.height;
+ op->render.source_rect.size.width = bounds->size.width / top->bounds.size.width;
+ op->render.source_rect.size.height = bounds->size.height / top->bounds.size.height;
+
+ op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
+ render,
+ uploader,
+ bottom,
+ &bottom->bounds,
+ clip,
+ &op->render.source2_rect);
+ op->render.source2_rect.origin.x = (bounds->origin.x - bottom->bounds.origin.x)/bottom->bounds.size.width;
+ op->render.source2_rect.origin.y = (bounds->origin.y - bottom->bounds.origin.y)/bottom->bounds.size.height;
+ op->render.source2_rect.size.width = bounds->size.width / bottom->bounds.size.width;
+ op->render.source2_rect.size.height = bounds->size.height / bottom->bounds.size.height;
+ }
+ break;
+
+ case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+ clip = &op->constants.constants.clip;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ case GSK_VULKAN_OP_COLOR:
+ case GSK_VULKAN_OP_LINEAR_GRADIENT:
+ case GSK_VULKAN_OP_BORDER:
+ case GSK_VULKAN_OP_INSET_SHADOW:
+ case GSK_VULKAN_OP_OUTSET_SHADOW:
+ break;
+ }
+ }
+}
+
+static gsize
+gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
+{
+ GskVulkanOp *op;
+ gsize n_bytes;
+ guint i;
+
+ n_bytes = 0;
+ for (i = 0; i < self->render_ops->len; i++)
+ {
+ op = &g_array_index (self->render_ops, GskVulkanOp, i);
+
+ switch (op->type)
+ {
+ case GSK_VULKAN_OP_FALLBACK:
+ case GSK_VULKAN_OP_FALLBACK_CLIP:
+ case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+ case GSK_VULKAN_OP_SURFACE:
+ case GSK_VULKAN_OP_TEXTURE:
+ case GSK_VULKAN_OP_REPEAT:
+ op->render.vertex_count = gsk_vulkan_texture_pipeline_count_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_TEXT:
+ op->text.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
+ op->text.num_glyphs);
+ n_bytes += op->text.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_COLOR_TEXT:
+ op->text.vertex_count = gsk_vulkan_color_text_pipeline_count_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->render.pipeline),
+ op->text.num_glyphs);
+ n_bytes += op->text.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_COLOR:
+ op->render.vertex_count = gsk_vulkan_color_pipeline_count_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_LINEAR_GRADIENT:
+ op->render.vertex_count = gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_OPACITY:
+ case GSK_VULKAN_OP_COLOR_MATRIX:
+ op->render.vertex_count = gsk_vulkan_effect_pipeline_count_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_BLUR:
+ op->render.vertex_count = gsk_vulkan_blur_pipeline_count_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_BORDER:
+ op->render.vertex_count = gsk_vulkan_border_pipeline_count_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_INSET_SHADOW:
+ case GSK_VULKAN_OP_OUTSET_SHADOW:
+ op->render.vertex_count = gsk_vulkan_box_shadow_pipeline_count_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_CROSS_FADE:
+ op->render.vertex_count = gsk_vulkan_cross_fade_pipeline_count_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
+ case GSK_VULKAN_OP_BLEND_MODE:
+ op->render.vertex_count = gsk_vulkan_blend_mode_pipeline_count_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
+ default:
+ g_assert_not_reached ();
+
+ case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+ continue;
+ }
+ }
+
+ return n_bytes;
+}
+
+static gsize
+gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ guchar *data,
+ gsize offset,
+ gsize total)
+{
+ GskVulkanOp *op;
+ gsize n_bytes;
+ guint i;
+
+ n_bytes = 0;
+ for (i = 0; i < self->render_ops->len; i++)
+ {
+ op = &g_array_index (self->render_ops, GskVulkanOp, i);
+
+ switch (op->type)
+ {
+ case GSK_VULKAN_OP_FALLBACK:
+ case GSK_VULKAN_OP_FALLBACK_CLIP:
+ case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+ case GSK_VULKAN_OP_SURFACE:
+ case GSK_VULKAN_OP_TEXTURE:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ &op->render.node->bounds,
+ &op->render.source_rect);
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_REPEAT:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_texture_pipeline_collect_vertex_data (GSK_VULKAN_TEXTURE_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ &op->render.node->bounds,
+ &op->render.source_rect);
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_TEXT:
+ {
+ op->text.vertex_offset = offset + n_bytes;
+ gsk_vulkan_text_pipeline_collect_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
+ data + n_bytes + offset,
+ GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+ &op->text.node->bounds,
+ (PangoFont *)gsk_text_node_peek_font (op->text.node),
+ gsk_text_node_get_num_glyphs (op->text.node),
+ gsk_text_node_peek_glyphs (op->text.node),
+ gsk_text_node_peek_color (op->text.node),
+ gsk_text_node_get_x (op->text.node),
+ gsk_text_node_get_y (op->text.node),
+ op->text.start_glyph,
+ op->text.num_glyphs,
+ op->text.scale);
+ n_bytes += op->text.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_COLOR_TEXT:
+ {
+ op->text.vertex_offset = offset + n_bytes;
+ gsk_vulkan_color_text_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->text.pipeline),
+ data + n_bytes + offset,
+ GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+ &op->text.node->bounds,
+ (PangoFont *)gsk_text_node_peek_font (op->text.node),
+ gsk_text_node_get_num_glyphs (op->text.node),
+ gsk_text_node_peek_glyphs (op->text.node),
+ gsk_text_node_get_x (op->text.node),
+ gsk_text_node_get_y (op->text.node),
+ op->text.start_glyph,
+ op->text.num_glyphs,
+ op->text.scale);
+ n_bytes += op->text.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_COLOR:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_color_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ &op->render.node->bounds,
+ gsk_color_node_peek_color (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_LINEAR_GRADIENT:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ &op->render.node->bounds,
+ gsk_linear_gradient_node_peek_start (op->render.node),
+ gsk_linear_gradient_node_peek_end (op->render.node),
+ gsk_render_node_get_node_type (op->render.node) == GSK_REPEATING_LINEAR_GRADIENT_NODE,
+ gsk_linear_gradient_node_get_n_color_stops (op->render.node),
+ gsk_linear_gradient_node_peek_color_stops (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_OPACITY:
+ {
+ graphene_matrix_t color_matrix;
+ graphene_vec4_t color_offset;
+
+ graphene_matrix_init_from_float (&color_matrix,
+ (float[16]) {
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, gsk_opacity_node_get_opacity (op->render.node)
+ });
+ graphene_vec4_init (&color_offset, 0.0, 0.0, 0.0, 0.0);
+ op->render.vertex_offset = offset + n_bytes;
+
+ gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ &op->render.node->bounds,
+ &op->render.source_rect,
+ &color_matrix,
+ &color_offset);
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_BLUR:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_blur_pipeline_collect_vertex_data (GSK_VULKAN_BLUR_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ &op->render.node->bounds,
+ &op->render.source_rect,
+ gsk_blur_node_get_radius (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_COLOR_MATRIX:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ &op->render.node->bounds,
+ &op->render.source_rect,
+ gsk_color_matrix_node_peek_color_matrix (op->render.node),
+ gsk_color_matrix_node_peek_color_offset (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_BORDER:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_border_pipeline_collect_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ gsk_border_node_peek_outline (op->render.node),
+ gsk_border_node_peek_widths (op->render.node),
+ gsk_border_node_peek_colors (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_INSET_SHADOW:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ gsk_inset_shadow_node_peek_outline (op->render.node),
+ gsk_inset_shadow_node_peek_color (op->render.node),
+ gsk_inset_shadow_node_get_dx (op->render.node),
+ gsk_inset_shadow_node_get_dy (op->render.node),
+ gsk_inset_shadow_node_get_spread (op->render.node),
+ gsk_inset_shadow_node_get_blur_radius (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_OUTSET_SHADOW:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GSK_VULKAN_BOX_SHADOW_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ gsk_outset_shadow_node_peek_outline (op->render.node),
+ gsk_outset_shadow_node_peek_color (op->render.node),
+ gsk_outset_shadow_node_get_dx (op->render.node),
+ gsk_outset_shadow_node_get_dy (op->render.node),
+ gsk_outset_shadow_node_get_spread (op->render.node),
+ gsk_outset_shadow_node_get_blur_radius (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_CROSS_FADE:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ &op->render.node->bounds,
+ &op->render.source_rect,
+ &op->render.source2_rect,
+ gsk_cross_fade_node_get_progress (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ case GSK_VULKAN_OP_BLEND_MODE:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GSK_VULKAN_BLEND_MODE_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ &op->render.node->bounds,
+ &op->render.source_rect,
+ &op->render.source2_rect,
+ gsk_blend_node_get_blend_mode (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+ continue;
+ }
+
+ g_assert (n_bytes + offset <= total);
+ }
+
+ return n_bytes;
+}
+
+static GskVulkanBuffer *
+gsk_vulkan_render_pass_get_vertex_data (GskVulkanRenderPass *self,
+ GskVulkanRender *render)
+{
+ if (self->vertex_data == NULL)
+ {
+ gsize n_bytes;
+ guchar *data;
+
+ n_bytes = gsk_vulkan_render_pass_count_vertex_data (self);
+ self->vertex_data = gsk_vulkan_buffer_new (self->vulkan, n_bytes);
+ data = gsk_vulkan_buffer_map (self->vertex_data);
+ gsk_vulkan_render_pass_collect_vertex_data (self, render, data, 0, n_bytes);
+ gsk_vulkan_buffer_unmap (self->vertex_data);
+ }
+
+ return self->vertex_data;
+}
+
+gsize
+gsk_vulkan_render_pass_get_wait_semaphores (GskVulkanRenderPass *self,
+ VkSemaphore **semaphores)
+{
+ *semaphores = (VkSemaphore *)self->wait_semaphores->data;
+ return self->wait_semaphores->len;
+}
+
+gsize
+gsk_vulkan_render_pass_get_signal_semaphores (GskVulkanRenderPass *self,
+ VkSemaphore **semaphores)
+{
+ *semaphores = (VkSemaphore *)&self->signal_semaphore;
+ return self->signal_semaphore != VK_NULL_HANDLE ? 1 : 0;
+}
+
+void
+gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
+ GskVulkanRender *render)
+{
+ GskVulkanOp *op;
+ guint i;
+
+ for (i = 0; i < self->render_ops->len; i++)
+ {
+ op = &g_array_index (self->render_ops, GskVulkanOp, i);
+
+ switch (op->type)
+ {
+ case GSK_VULKAN_OP_FALLBACK:
+ case GSK_VULKAN_OP_FALLBACK_CLIP:
+ case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+ case GSK_VULKAN_OP_SURFACE:
+ case GSK_VULKAN_OP_TEXTURE:
+ case GSK_VULKAN_OP_OPACITY:
+ case GSK_VULKAN_OP_BLUR:
+ case GSK_VULKAN_OP_COLOR_MATRIX:
+ if (op->render.source)
+ op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
+ break;
+
+ case GSK_VULKAN_OP_REPEAT:
+ if (op->render.source)
+ op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, TRUE);
+ break;
+
+ case GSK_VULKAN_OP_TEXT:
+ case GSK_VULKAN_OP_COLOR_TEXT:
+ op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source, FALSE);
+ break;
+
+ case GSK_VULKAN_OP_CROSS_FADE:
+ case GSK_VULKAN_OP_BLEND_MODE:
+ if (op->render.source && op->render.source2)
+ {
+ op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
+ op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE);
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+
+ case GSK_VULKAN_OP_COLOR:
+ case GSK_VULKAN_OP_LINEAR_GRADIENT:
+ case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+ case GSK_VULKAN_OP_BORDER:
+ case GSK_VULKAN_OP_INSET_SHADOW:
+ case GSK_VULKAN_OP_OUTSET_SHADOW:
+ break;
+ }
+ }
+}
+
+static void
+gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ guint layout_count,
+ VkPipelineLayout *pipeline_layout,
+ VkCommandBuffer command_buffer)
+{
+ GskVulkanPipeline *current_pipeline = NULL;
+ gsize current_draw_index = 0;
+ GskVulkanOp *op;
+ guint i, step;
+ GskVulkanBuffer *vertex_buffer;
+
+ vertex_buffer = gsk_vulkan_render_pass_get_vertex_data (self, render);
+
+ for (i = 0; i < self->render_ops->len; i += step)
+ {
+ op = &g_array_index (self->render_ops, GskVulkanOp, i);
+ step = 1;
+
+ switch (op->type)
+ {
+ case GSK_VULKAN_OP_FALLBACK:
+ case GSK_VULKAN_OP_FALLBACK_CLIP:
+ case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
+ case GSK_VULKAN_OP_SURFACE:
+ case GSK_VULKAN_OP_TEXTURE:
+ case GSK_VULKAN_OP_REPEAT:
+ if (!op->render.source)
+ continue;
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+
+ vkCmdBindDescriptorSets (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+ 0,
+ 1,
+ (VkDescriptorSet[1]) {
+ gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
+ },
+ 0,
+ NULL);
+
+ current_draw_index += gsk_vulkan_texture_pipeline_draw (GSK_VULKAN_TEXTURE_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, 1);
+ break;
+
+ case GSK_VULKAN_OP_TEXT:
+ if (current_pipeline != op->text.pipeline)
+ {
+ current_pipeline = op->text.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->text.vertex_offset });
+ current_draw_index = 0;
+ }
+
+ vkCmdBindDescriptorSets (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+ 0,
+ 1,
+ (VkDescriptorSet[1]) {
+ gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
+ },
+ 0,
+ NULL);
+
+ current_draw_index += gsk_vulkan_text_pipeline_draw (GSK_VULKAN_TEXT_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, op->text.num_glyphs);
+ break;
+
+ case GSK_VULKAN_OP_COLOR_TEXT:
+ if (current_pipeline != op->text.pipeline)
+ {
+ current_pipeline = op->text.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->text.vertex_offset });
+ current_draw_index = 0;
+ }
+
+ vkCmdBindDescriptorSets (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+ 0,
+ 1,
+ (VkDescriptorSet[1]) {
+ gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
+ },
+ 0,
+ NULL);
+
+ current_draw_index += gsk_vulkan_color_text_pipeline_draw (GSK_VULKAN_COLOR_TEXT_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, op->text.num_glyphs);
+ break;
+
+ case GSK_VULKAN_OP_OPACITY:
+ case GSK_VULKAN_OP_COLOR_MATRIX:
+ if (!op->render.source)
+ continue;
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+
+ vkCmdBindDescriptorSets (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+ 0,
+ 1,
+ (VkDescriptorSet[1]) {
+ gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
+ },
+ 0,
+ NULL);
+
+ current_draw_index += gsk_vulkan_effect_pipeline_draw (GSK_VULKAN_EFFECT_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, 1);
+ break;
+
+ case GSK_VULKAN_OP_BLUR:
+ if (!op->render.source)
+ continue;
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+
+ vkCmdBindDescriptorSets (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+ 0,
+ 1,
+ (VkDescriptorSet[1]) {
+ gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
+ },
+ 0,
+ NULL);
+
+ current_draw_index += gsk_vulkan_blur_pipeline_draw (GSK_VULKAN_BLUR_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, 1);
+ break;
+
+ case GSK_VULKAN_OP_COLOR:
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+
+ for (step = 1; step + i < self->render_ops->len; step++)
+ {
+ GskVulkanOp *cmp = &g_array_index (self->render_ops, GskVulkanOp, i + step);
+ if (cmp->type != GSK_VULKAN_OP_COLOR ||
+ cmp->render.pipeline != current_pipeline)
+ break;
+ }
+ current_draw_index += gsk_vulkan_color_pipeline_draw (GSK_VULKAN_COLOR_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, step);
+ break;
+
+ case GSK_VULKAN_OP_LINEAR_GRADIENT:
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+ current_draw_index += gsk_vulkan_linear_gradient_pipeline_draw (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, 1);
+ break;
+
+ case GSK_VULKAN_OP_BORDER:
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+ current_draw_index += gsk_vulkan_border_pipeline_draw (GSK_VULKAN_BORDER_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, 1);
+ break;
+
+ case GSK_VULKAN_OP_INSET_SHADOW:
+ case GSK_VULKAN_OP_OUTSET_SHADOW:
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+ current_draw_index += gsk_vulkan_box_shadow_pipeline_draw (GSK_VULKAN_BOX_SHADOW_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, 1);
+ break;
+
+ case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+ for (int i = 0; i < layout_count; i++)
+ gsk_vulkan_push_constants_push (&op->constants.constants,
+ command_buffer,
+ pipeline_layout[i]);
+ break;
+
+ case GSK_VULKAN_OP_CROSS_FADE:
+ if (!op->render.source || !op->render.source2)
+ continue;
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+
+ vkCmdBindDescriptorSets (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+ 0,
+ 2,
+ (VkDescriptorSet[2]) {
+ gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
+ gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
+ },
+ 0,
+ NULL);
+
+ current_draw_index += gsk_vulkan_cross_fade_pipeline_draw (GSK_VULKAN_CROSS_FADE_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, 1);
+ break;
+
+ case GSK_VULKAN_OP_BLEND_MODE:
+ if (!op->render.source || !op->render.source2)
+ continue;
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+
+ vkCmdBindDescriptorSets (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
+ 0,
+ 2,
+ (VkDescriptorSet[2]) {
+ gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index),
+ gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2)
+ },
+ 0,
+ NULL);
+
+ current_draw_index += gsk_vulkan_blend_mode_pipeline_draw (GSK_VULKAN_BLEND_MODE_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, 1);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+}
+
+void
+gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ guint layout_count,
+ VkPipelineLayout *pipeline_layout,
+ VkCommandBuffer command_buffer)
+{
+ guint i;
+
+ vkCmdSetViewport (command_buffer,
+ 0,
+ 1,
+ &(VkViewport) {
+ .x = 0,
+ .y = 0,
+ .width = self->viewport.size.width,
+ .height = self->viewport.size.height,
+ .minDepth = 0,
+ .maxDepth = 1
+ });
+
+ for (i = 0; i < cairo_region_num_rectangles (self->clip); i++)
+ {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (self->clip, i, &rect);
+
+ vkCmdSetScissor (command_buffer,
+ 0,
+ 1,
+ &(VkRect2D) {
+ { rect.x * self->scale_factor, rect.y * self->scale_factor },
+ { rect.width * self->scale_factor, rect.height * self->scale_factor }
+ });
+
+ vkCmdBeginRenderPass (command_buffer,
+ &(VkRenderPassBeginInfo) {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+ .renderPass = self->render_pass,
+ .framebuffer = gsk_vulkan_render_get_framebuffer (render, self->target),
+ .renderArea = {
+ { rect.x * self->scale_factor, rect.y * self->scale_factor },
+ { rect.width * self->scale_factor, rect.height * self->scale_factor }
+ },
+ .clearValueCount = 1,
+ .pClearValues = (VkClearValue [1]) {
+ { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
+ }
+ },
+ VK_SUBPASS_CONTENTS_INLINE);
+
+ gsk_vulkan_render_pass_draw_rect (self, render, layout_count, pipeline_layout, command_buffer);
+
+ vkCmdEndRenderPass (command_buffer);
+ }
+}
--- /dev/null
+#ifndef __GSK_VULKAN_RENDER_PASS_PRIVATE_H__
+#define __GSK_VULKAN_RENDER_PASS_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <gsk/gskrendernode.h>
+
+#include "gskvulkanbufferprivate.h"
+#include "gskvulkanrenderprivate.h"
+#include "gsk/gskprivate.h"
+
+G_BEGIN_DECLS
+
+
+GskVulkanRenderPass * gsk_vulkan_render_pass_new (GdkVulkanContext *context,
+ GskVulkanImage *target,
+ int scale_factor,
+ graphene_matrix_t *mv,
+ graphene_rect_t *viewport,
+ cairo_region_t *clip,
+ VkSemaphore signal_semaphore);
+
+void gsk_vulkan_render_pass_free (GskVulkanRenderPass *self);
+
+void gsk_vulkan_render_pass_add (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ GskRenderNode *node);
+
+void gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ GskVulkanUploader *uploader);
+void gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
+ GskVulkanRender *render);
+void gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
+ GskVulkanRender *render,
+ guint layout_count,
+ VkPipelineLayout *pipeline_layout,
+ VkCommandBuffer command_buffer);
+gsize gsk_vulkan_render_pass_get_wait_semaphores (GskVulkanRenderPass *self,
+ VkSemaphore **semaphores);
+gsize gsk_vulkan_render_pass_get_signal_semaphores (GskVulkanRenderPass *self,
+ VkSemaphore **semaphores);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_RENDER_PASS_PRIVATE_H__ */
--- /dev/null
+#ifndef __GSK_VULKAN_RENDER_PRIVATE_H__
+#define __GSK_VULKAN_RENDER_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <gsk/gskrendernode.h>
+
+#include "gskvulkanimageprivate.h"
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrenderpassprivate.h"
+#include "gsk/gskprivate.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GSK_VULKAN_PIPELINE_TEXTURE,
+ GSK_VULKAN_PIPELINE_TEXTURE_CLIP,
+ GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_COLOR,
+ GSK_VULKAN_PIPELINE_COLOR_CLIP,
+ GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_LINEAR_GRADIENT,
+ GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP,
+ GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_COLOR_MATRIX,
+ GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP,
+ GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_BORDER,
+ GSK_VULKAN_PIPELINE_BORDER_CLIP,
+ GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_INSET_SHADOW,
+ GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP,
+ GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_OUTSET_SHADOW,
+ GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP,
+ GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_BLUR,
+ GSK_VULKAN_PIPELINE_BLUR_CLIP,
+ GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_TEXT,
+ GSK_VULKAN_PIPELINE_TEXT_CLIP,
+ GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_COLOR_TEXT,
+ GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP,
+ GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_CROSS_FADE,
+ GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP,
+ GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_BLEND_MODE,
+ GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP,
+ GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED,
+ /* add more */
+ GSK_VULKAN_N_PIPELINES
+} GskVulkanPipelineType;
+
+GskVulkanRender * gsk_vulkan_render_new (GskRenderer *renderer,
+ GdkVulkanContext *context);
+void gsk_vulkan_render_free (GskVulkanRender *self);
+
+gboolean gsk_vulkan_render_is_busy (GskVulkanRender *self);
+void gsk_vulkan_render_reset (GskVulkanRender *self,
+ GskVulkanImage *target,
+ const graphene_rect_t *rect);
+
+GskRenderer * gsk_vulkan_render_get_renderer (GskVulkanRender *self);
+
+void gsk_vulkan_render_add_cleanup_image (GskVulkanRender *self,
+ GskVulkanImage *image);
+
+void gsk_vulkan_render_add_node (GskVulkanRender *self,
+ GskRenderNode *node);
+
+void gsk_vulkan_render_add_render_pass (GskVulkanRender *self,
+ GskVulkanRenderPass *pass);
+
+void gsk_vulkan_render_upload (GskVulkanRender *self);
+
+GskVulkanPipeline * gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
+ GskVulkanPipelineType pipeline_type);
+VkDescriptorSet gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
+ gsize id);
+gsize gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
+ GskVulkanImage *source,
+ gboolean repeat);
+void gsk_vulkan_render_draw (GskVulkanRender *self);
+
+void gsk_vulkan_render_submit (GskVulkanRender *self);
+
+GdkTexture * gsk_vulkan_render_download_target (GskVulkanRender *self);
+VkFramebuffer gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
+ GskVulkanImage *image);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_RENDER_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanshaderprivate.h"
+#include "gskvulkanpipelineprivate.h"
+
+struct _GskVulkanShader
+{
+ GdkVulkanContext *vulkan;
+
+ GskVulkanShaderType type;
+ VkShaderModule vk_shader;
+};
+
+static GskVulkanShader *
+gsk_vulkan_shader_new_from_bytes (GdkVulkanContext *context,
+ GskVulkanShaderType type,
+ GBytes *bytes,
+ GError **error)
+{
+ GskVulkanShader *self;
+ VkShaderModule shader;
+ VkResult res;
+
+ res = GSK_VK_CHECK (vkCreateShaderModule, gdk_vulkan_context_get_device (context),
+ &(VkShaderModuleCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+ .codeSize = g_bytes_get_size (bytes),
+ .pCode = (uint32_t *) g_bytes_get_data (bytes, NULL),
+ },
+ NULL,
+ &shader);
+ if (res != VK_SUCCESS)
+ {
+ /* Someone invent better error categories plz */
+ g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
+ "Could not create shader: %s", gdk_vulkan_strerror (res));
+ return NULL;
+ }
+
+ self = g_slice_new0 (GskVulkanShader);
+
+ self->vulkan = g_object_ref (context);
+ self->type = type;
+ self->vk_shader = shader;
+
+ return self;
+}
+
+GskVulkanShader *
+gsk_vulkan_shader_new_from_resource (GdkVulkanContext *context,
+ GskVulkanShaderType type,
+ const char *resource_name,
+ GError **error)
+{
+ GskVulkanShader *self;
+ GBytes *bytes;
+ GError *local_error = NULL;
+ char *path;
+
+ path = g_strconcat ("/org/gtk/libgsk/vulkan/",
+ resource_name,
+ type == GSK_VULKAN_SHADER_VERTEX ? ".vert.spv" : ".frag.spv",
+ NULL);
+ bytes = g_resources_lookup_data (path, 0, &local_error);
+ g_free (path);
+ if (bytes == NULL)
+ {
+ GSK_NOTE (VULKAN, g_printerr ("Error loading shader data: %s\n", local_error->message));
+ g_propagate_error (error, local_error);
+ return NULL;
+ }
+
+ self = gsk_vulkan_shader_new_from_bytes (context, type, bytes, error);
+ g_bytes_unref (bytes);
+
+ return self;
+}
+
+void
+gsk_vulkan_shader_free (GskVulkanShader *self)
+{
+ vkDestroyShaderModule (gdk_vulkan_context_get_device (self->vulkan),
+ self->vk_shader,
+ NULL);
+
+ g_object_unref (self->vulkan);
+
+ g_slice_free (GskVulkanShader, self);
+}
+
+GskVulkanShaderType
+gsk_vulkan_shader_get_type (GskVulkanShader *shader)
+{
+ return shader->type;
+}
+
+VkShaderModule
+gsk_vulkan_shader_get_module (GskVulkanShader *shader)
+{
+ return shader->vk_shader;
+}
+
--- /dev/null
+#ifndef __GSK_VULKAN_SHADER_PRIVATE_H__
+#define __GSK_VULKAN_SHADER_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GSK_VULKAN_SHADER_VERTEX,
+ GSK_VULKAN_SHADER_FRAGMENT
+} GskVulkanShaderType;
+
+typedef struct _GskVulkanShader GskVulkanShader;
+
+#define GST_VULKAN_SHADER_STAGE_CREATE_INFO(shader) \
+ (VkPipelineShaderStageCreateInfo) { \
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, \
+ .stage = gsk_vulkan_shader_get_type (shader) == GSK_VULKAN_SHADER_VERTEX ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, \
+ .module = gsk_vulkan_shader_get_module (shader), \
+ .pName = "main", \
+}
+
+GskVulkanShader * gsk_vulkan_shader_new_from_resource (GdkVulkanContext *context,
+ GskVulkanShaderType type,
+ const char *resource_name,
+ GError **error);
+void gsk_vulkan_shader_free (GskVulkanShader *shader);
+
+GskVulkanShaderType gsk_vulkan_shader_get_type (GskVulkanShader *shader);
+VkShaderModule gsk_vulkan_shader_get_module (GskVulkanShader *shader);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_SHADER_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkantextpipelineprivate.h"
+
+struct _GskVulkanTextPipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanTextInstance GskVulkanTextInstance;
+
+struct _GskVulkanTextInstance
+{
+ float rect[4];
+ float tex_rect[4];
+ float color[4];
+};
+
+G_DEFINE_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanTextInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, rect),
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, tex_rect),
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanTextInstance, color),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_text_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanTextPipeline *self = GSK_VULKAN_TEXT_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_text_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_text_pipeline_class_init (GskVulkanTextPipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_text_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_text_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_text_pipeline_init (GskVulkanTextPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_text_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new_full (GSK_TYPE_VULKAN_TEXT_PIPELINE, context, layout, shader_name, render_pass,
+ VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
+}
+
+gsize
+gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
+ int num_instances)
+{
+ return sizeof (GskVulkanTextInstance) * num_instances;
+}
+
+void
+gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
+ guchar *data,
+ GskVulkanRenderer *renderer,
+ const graphene_rect_t *rect,
+ PangoFont *font,
+ guint total_glyphs,
+ const PangoGlyphInfo *glyphs,
+ const GdkRGBA *color,
+ float x,
+ float y,
+ guint start_glyph,
+ guint num_glyphs,
+ float scale)
+{
+ GskVulkanTextInstance *instances = (GskVulkanTextInstance *) data;
+ int i;
+ int count = 0;
+ int x_position = 0;
+
+ for (i = 0; i < start_glyph; i++)
+ x_position += glyphs[i].geometry.width;
+
+ for (; i < total_glyphs && count < num_glyphs; i++)
+ {
+ const PangoGlyphInfo *gi = &glyphs[i];
+
+ if (gi->glyph != PANGO_GLYPH_EMPTY)
+ {
+ double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
+ double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE;
+ GskVulkanTextInstance *instance = &instances[count];
+ GskVulkanCachedGlyph *glyph;
+
+ glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale);
+
+ instance->tex_rect[0] = glyph->tx;
+ instance->tex_rect[1] = glyph->ty;
+ instance->tex_rect[2] = glyph->tw;
+ instance->tex_rect[3] = glyph->th;
+
+ instance->rect[0] = x + cx + glyph->draw_x;
+ instance->rect[1] = y + cy + glyph->draw_y;
+ instance->rect[2] = glyph->draw_width;
+ instance->rect[3] = glyph->draw_height;
+
+ instance->color[0] = color->red;
+ instance->color[1] = color->green;
+ instance->color[2] = color->blue;
+ instance->color[3] = color->alpha;
+
+ count++;
+ }
+ x_position += gi->geometry.width;
+ }
+}
+
+gsize
+gsk_vulkan_text_pipeline_draw (GskVulkanTextPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskvulkanrendererprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanTextPipelineLayout GskVulkanTextPipelineLayout;
+
+#define GSK_TYPE_VULKAN_TEXT_PIPELINE (gsk_vulkan_text_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK, VULKAN_TEXT_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_text_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
+ int num_instances);
+void gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
+ guchar *data,
+ GskVulkanRenderer *renderer,
+ const graphene_rect_t *rect,
+ PangoFont *font,
+ guint total_glyphs,
+ const PangoGlyphInfo *glyphs,
+ const GdkRGBA *color,
+ float x,
+ float y,
+ guint start_glyph,
+ guint num_glyphs,
+ float scale);
+gsize gsk_vulkan_text_pipeline_draw (GskVulkanTextPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_TEXT_PIPELINE_PRIVATE_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gskvulkantexturepipelineprivate.h"
+
+struct _GskVulkanTexturePipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanTextureInstance GskVulkanTextureInstance;
+
+struct _GskVulkanTextureInstance
+{
+ float rect[4];
+ float tex_rect[4];
+};
+
+G_DEFINE_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_texture_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanTextureInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, rect),
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, tex_rect),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_texture_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanTexturePipeline *self = GSK_VULKAN_TEXTURE_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_texture_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_texture_pipeline_class_init (GskVulkanTexturePipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_texture_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_texture_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_texture_pipeline_init (GskVulkanTexturePipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_texture_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_TEXTURE_PIPELINE, context, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_texture_pipeline_count_vertex_data (GskVulkanTexturePipeline *pipeline)
+{
+ return sizeof (GskVulkanTextureInstance);
+}
+
+void
+gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const graphene_rect_t *tex_rect)
+{
+ GskVulkanTextureInstance *instance = (GskVulkanTextureInstance *) data;
+
+ instance->rect[0] = rect->origin.x;
+ instance->rect[1] = rect->origin.y;
+ instance->rect[2] = rect->size.width;
+ instance->rect[3] = rect->size.height;
+ instance->tex_rect[0] = tex_rect->origin.x;
+ instance->tex_rect[1] = tex_rect->origin.y;
+ instance->tex_rect[2] = tex_rect->size.width;
+ instance->tex_rect[3] = tex_rect->size.height;
+}
+
+gsize
+gsk_vulkan_texture_pipeline_draw (GskVulkanTexturePipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanTexturePipelineLayout GskVulkanTexturePipelineLayout;
+
+#define GSK_TYPE_VULKAN_TEXTURE_PIPELINE (gsk_vulkan_texture_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK, VULKAN_TEXTURE_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_texture_pipeline_new (GdkVulkanContext *context,
+ VkPipelineLayout layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_texture_pipeline_count_vertex_data (GskVulkanTexturePipeline *pipeline);
+void gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
+ guchar *data,
+ const graphene_rect_t *rect,
+ const graphene_rect_t *tex_rect);
+gsize gsk_vulkan_texture_pipeline_draw (GskVulkanTexturePipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_TEXTURE_PIPELINE_PRIVATE_H__ */